Visual Studio allows unit testing of private methods via an automatically generated accessor class. I have written a test of a private method that compiles successfully, but it fails at runtime. A fairly minimal version of the code and the test is:
//in project MyProj class TypeA { private List<TypeB> myList = new List<TypeB>(); private class TypeB { public TypeB() { } } public TypeA() { } private void MyFunc() { //processing of myList that changes state of instance } } //in project TestMyProj public void MyFuncTest() { TypeA_Accessor target = new TypeA_Accessor(); //following line is the one that throws exception target.myList.Add(new TypeA_Accessor.TypeB()); target.MyFunc(); //check changed state of target }
The runtime error is:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
According to intellisense - and hence I guess the compiler - target is of type TypeA_Accessor. But at runtime it is of type TypeA, and hence the list add fails.
Is there any way I can stop this error? Or, perhaps more likely, what other advice do other people have (I predict maybe "don't test private methods" and "don't have unit tests manipulate the state of objects").
Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.
The unit test should only test the public interface. Each private method is an implementation detail. They contain the logic necessary to implement a piece of functionality.
Protected methods form a different contract between your class and its future children, so you should really be testing it to a similar extent as your public interface to ensure that the contract is well defined and exercised.
You can use the PrivateObject
class:
Class target = new Class(); PrivateObject obj = new PrivateObject(target); var retVal = obj.Invoke("PrivateMethod"); Assert.AreEqual(expectedVal, retVal);
Note: PrivateObject
and PrivateType
are not available for projects targeting netcoreapp2.0 - GitHub Issue 366
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