Recently in order to implement unit testing for a private method of a class, I used PrivateObject by creating a private accessors instead of using Reflection, to which I received the following code review comment:
"My main concern with Private Object is the use of object[] in constructor. It replaces strong typing enforced by compiler with JavaScript-style run-time error detection.Consequently , personally, I would not recommend it."
This comment above confused me beacuse as per my understanding, Reflection also needs the object[]
to invoke any method. Please help me to understand what the best approach is.
This is called Test Specific Subclass or Test Specific Extension in great book Refactoring Test Code http://xunitpatterns.com/
You can read more details and ideas for testing private methods here : http://xunitpatterns.com/Test-Specific%20Subclass.html
It works like
public TestClass : RealClass
{
public int CallHiddenCalculate()
{
return Calculate(); // Calculate is now protected method that we expose for test purposes in this class
}
}
You can place this class to test assembly so your real assembly doesnt contain test specific logic and classes because its bad design.
#if DEBUG public #else private #endif
In this case in Debug you can call unit tests but in release those methods won't be visible. However this approach is much worse than the above and is more ugly too.
Testing just public interface can easily be not enough (and often is not) in order to say that you got good test coverage and your code is easy to maintain and refactor.
As for marking private methods as internal and having test assembly see internal methods is bad for many reasons
and I think there are more but those are most important
Interesting question. Generally, unit tests are meant to verify the public behavior of your classes, from the viewpoint of consumers of your classes. That is, the consumers don't care HOW you do it, so long as your class keeps the promises it makes.
If you REALLY need to expose 'private' members to unit test, mark them as internal and make them accessible via the InternalsVisibleTo attribute. It's ugly, but it works, and you can later keep it out of your assembly with some conditional compilation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With