Tuesday, 10 April 2007

How to make unit testing from another project in .NET

WARNING: all this blog post is crap (error of youth ;-). Don't do this. Never. Ever. Do not test implementation details.  Follow: https://tpierrain.blogspot.com/2021/03/outside-in-diamond-tdd-1-style-made.html instead.




There is a recurrent debate around the notion of unit testing: should we only test the contracts, the visible part? or should we test the "internal affairs" of our class? In my opinion, the first proposition isn't enough. Since our teams decided to write unit tests in separate .NET assemblies (because we do not deploy test code in production, but tested code ;-), I was forced to find a trick in order to be able to query the private state of tested objects, without breaking the encapsulation. This trick is the .NET explicit interface implementation mecanism. "An interface member that is explicitly implemented cannot be accessed from a class instance, but only if the class instance is cast into the given interface." eg:
// Interface for testing purpose only, // (we always use a name like: // I<ClassToTestName>ForTesting) public interface IBoyForTesting { bool AlreadySpentAdolescentCrisis {get;} } // The class to test public class Boy : IBoyForTesting { private int age; private bool alreadySpentAdolescentCrisis; public int Age { get { return this.age; } } // Explicit interface member implementation: bool IBoyForTesting.AlreadySpentAdolescentCrisis { get { return this. alreadySpentAdolescentCrisis; } } /* ... */ } // Unit testing sample int age = 20; Boy aBoy = new Boy(age); // The following commented line would produce // compilation error because it try to access an // explicitly implemented member // bool isAdult = aBoy.AlreadySpentAdolescentCrisis; // To test this "almost private" information, you can write: Assert.IsTrue( ((IBoyForTesting)aBoy). AlreadySpentAdolescentCrisis );
With the .NET interface explicit implementation feature, you can test your classes from the outside, without too much having to break the encapsulation.