Tuesday, April 15, 2008

Unit Testing of Non Public Class and Method

Testing private, internal and protected class and method has always been a debatable issue in the test driven development world. Recently, while working on a project, I have to test all these non public classes and methods as there are some complex logic in it and their accessibility have to be restricted. In order, to ensure each method is working correctly, unit test have to be conducted on them from another test project.

The whole solution is structure in such a way that the test project is separated from the application project. Will not going into the discussion on how the project for the actual code and test should be structured, but here a poll result on the preference. Since the test project is separated from the application project, the test project will not have any access to the internal access modifier class and method.

Tim Stall has provided a great overview on testing these non public methods and a helper class in Code Project for those that need to test them. While working on the test, I have encountered other problems with scenario like Expected Exception Testing of Private Method and Internal Class with Private Static Method which the helper class utility were unable to take care of. Therefore, after some research and testing, I have made some modification to the code and how the helper class method can be called to take care of the 2 scenarios mentioned above.

Expected Exception Testing of Private Method
The helper class provided by Tim Stall makes testing of private method so much easier, but what happen when the private method will throw exception in some scenario and how can such test be done? Excepted Exception can be used to test for exception thrown by a method, however with the helper class, any exception throw from the actual method will be wrapped with the System.Reflection.TargetInvocationException. This will prevent the actual exception to be captured by the test. In order to capture the actual exception, the catch in the RunMethod found in the helper class have to be replaced with the following code:
catch (Exception ex)
{
if (ex.InnerException != null)
throw ex.GetBaseException();
else
throw;
}
When an exception have been rethrow, the InnerException property should contain a reference to the base exception and it will be null if the exception is the original exception thrown. Therefore if the exception captured above is not the base exception, it will re-thrown the base (actual) exception so that it can be captured by the test.

Internal Class with Private Method
To test a private method with a public class, the RunStaticMethod have to be called with the following parameters:
RunStaticMethod(System.Type t, string strMethod, object[] aobjParams)
Since the class itself is internal, the reference of the object cannot be done from the test project (compile error when trying to reference to an internal class). To workaround this issue, some people have suggested to make the application project and test project as friend assemblies, but this follow on with other complication such as StrongNameIdentity and Public Key thingy. With the use of reflection and 2 lines of codes, the System Type of the internal class can be gotten to be input into the RunStaticMethod.

Firstly, get the reference assembly of the internal class using the reference of a public class belong to the same assembly:
System.Reflection.Assembly assembly = Assembly.GetAssembly(typeof(PublicClass));
Secondly, get the system type of the internal class to be input into RunStaticMethod with this:
System.Type sysType = assembly.GetType("TechRockGuy.InternalClass");
With these 2 scenarios, I guess other combination of class and method access modifier can be taken care of with the helper class and the modification made here. For those that need to test a private class with private method, how the instantiation of a new object is not mentioned here, but with dependency injection that should be able to help.

No comments: