简体   繁体   中英

C#: Mocking and testing protected (or private) methods in sealed classes — approaches

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?

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.

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 (ie only public interface).

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.

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);

您可以使用一些框架进行模拟 - 例如JustMock (通过Telerik)支持模拟密封的私有方法......不幸的是,JustMock的这部分是付费的,我想,但至少你可以尝试试用版。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM