11 June 2010

Making internals unit testable

When creating - or attempting to create ;-) - reusable components, it’s common practice to hide the gory details of your implementation – not only on class level, but also on assembly level. The drawback of this approach is that you cannot write unit tests to test low-level operations of your component – invisible to the world means invisible to your assembly with unit tests as well.

One approach is to make the component that is to be tested public after all – I admit I did it a couple of times in my wee days before I learned of this trick that actually dates back to .NET 2.0 if I am correct.

Let us assume you have a library MyCompany.GreatObjects.dll, in which you have a component MyCompany.GreatObjects.Internals.MyInternalComponent, and a test library in MyCompany.GreatObjects.Test.dll.

1. Strongly name your test project

Say what? No, I am getting older but I am still not senile (or at least no-one dared to tell me yet). If you don’t know what I mean with strong naming, follow the procedure described here. You might want to strongly name your project to be tested as well, when you are at it ;-) And then build your solution again.

2. Open a Visual Studio Command Prompt

Open the command prompt belonging to the version of Visual Studio you are currently using to develop and test your components. Navigate to the bin/debug subdirectory of your MyCompany.GreatObjects project.

3. Retrieve the public key of your component

Enter the following command:
sn –Tp MyCompany.GreatObjects.dll

This will give two answers – the first one, preceded by the text “Public key is” is the one you are after. It will span something like four and a bit lines and look like this:

Copy that code into a text file and carefully remove all line breaks, so that all these characters end up in one line. Take care not to remove any other character or your name is mud.

4. Edit the AssemblyInfo.cs of the component project

This file sits in the “Properties” application folder of your MyCompany.GreatObjects project.  Add the following line (where does not matter, but the end is a logical place):
[assembly: InternalsVisibleTo("MyCompany.GreatObjects.Test, PublicKey=****")]
replace the **** by the actual value for the public key you retrieved – on one line.
Rebuild the MyCompany.GreatObjects project, and you are done. You can now test MyCompany.GreatObjects.Internals.MyInternalComponent and other objects marked as internal, of course - from MyCompany.GreatObjects.Test. But only from MyCompany.GreatObjects.Test. For the rest of the world the internals are still safely invisible.

Purists might say that you only need to test external behavior of your component, but I can think of plenty of scenarios in which you want to change the working of an internal piece of code and still want to be able to verify its behavior – internal or not.

Credits go to my colleague Valentijn Makkenze for pointing this out to me first

1 comment:

peSHIr said...

Another option might be to use VisualStudio private accessors. This also works on private members of classes.

Simply right click a private member, choose Create private accessor and select/create a test project in your solution. In that solution, in a Test References folder, you'll get a file with .accessor extension.

After that, in your tests you should be able to use X_Accessor for X and on that static class and/or class instance you should not only see public members that you can use, but private ones too.