5

I have a sealed class with protected methods whose behaviour I want to test. This makes it hard to test directly, and hard to mock.

It's in a codebase that wasn't developed in a TDD manner, and I'm now adding unit tests for specific functionality.

What are the general approaches possible in this case? At the moment I have:

  1. Have the class unsealed. Then create a proxy or adapter derived from the class in our test code to tunnel access to the protected method.
  2. Factor out the behaviour in the protected method to a delegate/functor, and re-inject it. Then test the factored out behaviour independently.
  3. Test by calling the closest public method in the inheritance hierarchy that uses the protected method. Potentially leads to lots of mocking, and exposure to risk when code other than that under test changes -- creating fragile tests.
  4. Use reflection to get access to the protected method. Then call it directly.

Are there any more?

Tim Barrass
  • 4,813
  • 2
  • 29
  • 55

5 Answers5

8

A protected method in a sealed class is effectively the same as private (I guess if you seal a derived class where the base class has a protected member these can come up naturally.)

And there's no point testing private methods. Because they have no public behavior except that which is accessible through the public methods of the defining class, their behavior should be tested by testing the public methods.

jason
  • 236,483
  • 35
  • 423
  • 525
  • some times in order to test a public method, it is convenient to mock a private method. I think, that is the main use case – anthares Jan 20 '11 at 14:45
  • @anthares: That sounds misguided. If the `private` method is part of the implementation of the `public` method it should not be mocked out. – jason Jan 20 '11 at 14:48
  • Well, to give you an example: it's just taken me a good half day to even get close to mocking out everything I need just to call a certain protected method directly, using reflection. If I have to mock everything out from the nearest public method I may have to pass the task onto my children for completion. That's not to say that I don't agree with you in general -- just that with some codebases there are other practical constraints. (and +1) – Tim Barrass Jan 20 '11 at 14:56
  • 3
    @Tim Barrass: I think I'm talking past you. My point is that you shouldn't need to mock a protected method on a sealed class. It's the same as private, and private methods shouldn't be tested beyond the implicit tests from testing the public methods. Anytime you spend half a day on something, or fear that your children will inherit the work, you should take a step back and ask if it's worth it. Cost/benefit is key here. – jason Jan 20 '11 at 15:38
  • No, I think we're making the same point from different sides; you're exactly right about cost/benefit. – Tim Barrass Jan 20 '11 at 15:49
  • I agree with Jason that there is no point in testing private methods explicitly as that can be covered as part of the public methods of the defining class. But, there are some situation in which mocking out of private methods would help a lot in testing public methods. If you create the private members accessor class for a class and then create the .mole assembly for the class, then somehow the mole class contains all the public members as well as the private members and you can easily moled out (mock) your private methods. – 123Developer Aug 25 '11 at 12:09
3

Microsoft Moles helps mocking unsealed classes with non-virtual methods. It can't mock private methods, but this is redundant, because you can mock higher level public methods, that used outside particular class and you can emulate all necessary behaviour mocking one public method.

And why you should test private/protected methods? You can use internal methods and InternalVisibleToAttribute to achieve this. But in general you should test only public behaviour (i.e. only public interface).

Sergey Teplyakov
  • 11,477
  • 34
  • 49
  • Thanks for the Moles pointer, very interesting. I made a quick reply to Jason about mocking the public methods. – Tim Barrass Jan 20 '11 at 14:58
2

I would generally go for the second option assuming that you have the ability to make the changes reasonably easy. Given that if you cannot test what a protected /private method is doing through it's public interface it probably isn't conforming to Single responsibility principle anyway and the code could probably do with being broken into two classes and use composition instead.

Kev Hunter
  • 2,565
  • 4
  • 25
  • 39
1

You could use the JustMock framework. For example:

double value = 0;
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal);
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);
Hermann Döppes
  • 1,373
  • 1
  • 18
  • 26
Sergii Fasolko
  • 188
  • 1
  • 7
1

You can use some framework for mocking - for example JustMock (by Telerik) supports mock of sealed private methods ... Unfortunately, this part of JustMock is paid, I think, but at least you can try the trial version.

anthares
  • 11,070
  • 4
  • 41
  • 61