.Net Tips — using InternalsVisibleTo attribute to help testing non-public methods

Oh, the Pain!

For a long time, unit test­ing non-pub­lic meth­ods in C# has been a pain in the back side. In order to test a non-pub­lic method (most like­ly pri­vate meth­ods) you have a num­ber of choic­es each with an unde­sired effect:

  1. The eas­i­est way out is to make the meth­ods pub­lic. How­ev­er, this breaks all the encap­su­la­tions in your appli­ca­tion and can be poten­tial­ly unsafe because in most cas­es these meth­ods were not exposed pub­licly for a rea­son, e.g. a method which can leave your appli­ca­tion in a bad state if used incor­rect­ly.
  2. If mak­ing the meth­ods pub­lic is a step too far, you can make these meth­ods pro­tect­ed instead and have the unit test class extend this class to gain access to the pro­tect­ed meth­ods. Still, this breaks the encap­su­la­tion in your appli­ca­tion some­what, and hav­ing a unit test class extend a busi­ness log­ic class ‘smells’. And once again, it can be unsafe as oth­ers can also extend your class to gain unin­tend­ed access to these meth­ods, the same rea­son why you would often want to seal the LAST type in an inher­i­tance hier­ar­chy – to mark and pro­tect the bound­aries of your appli­ca­tion.
  3. The last and the most advanced tech­nique is to use reflec­tion to invoke these meth­ods. The upside is that you won’t have to break the encap­su­la­tion of your appli­ca­tion just to make them testable, the down­side is that you pay for this in main­tain­abil­i­ty and com­plex­i­ty. What it means is that your test class now needs to have inti­mate knowl­edge of the class it is test­ing and because meth­ods names are spelled out in string lit­er­als, renam­ing the non-pub­lic method becomes a more cost­ly oper­a­tion because you need to change all the reflec­tion code used to invoke the method too. Per­son­al­ly this is my least favourite approach as the fre­quen­cy of change and the num­ber of unit tests in any siz­able project can make the task of main­tain­ing them rather unen­vi­able (espe­cial­ly if it’s your job to do so!).

There’s a better way

Since .Net 2.0, you have anoth­er alter­na­tive thanks to the intro­duc­tion of the Inter­nalsVis­i­ble­To attribute. It gives you the abil­i­ty to expose meth­ods marked inter­nal to a spe­cif­ic assem­bly.

All you need to do is add one line of code to the AssemblyInfo.cs file of the assem­bly (say, MyAp­pli­ca­toin) you want to test to allow your unit test assem­bly (let’s call it MyApplication.Test) to see all the types/methods that have been marked with the inter­nal access mod­i­fi­er:

[assembly: InternalsVisibleTo("MyApplication.Test")]

You will also need to change the access mod­i­fi­er on any meth­ods (in MyAp­pli­ca­tion) you wish to test to inter­nal for you to be able to see it in MyApplication.Test.

Doing so, how­ev­er, doesn’t stop you from seal­ing your type (point 2 above) and doesn’t break all the encap­su­la­tion of your appli­ca­tion (meth­ods are still inac­ces­si­ble from exter­nal assem­blies besides the unit test assem­bly) although it still breaks the encap­su­la­tion of your type because any pri­vate meth­ods you wish to test have to be made inter­nal instead and there­fore acces­si­ble from out­side the type.

This is still not ide­al, but com­pared to the alter­na­tives, is still the one that I’m most will­ing to live with.

Parting thoughts…

Before you jump in with both feet and start test­ing all the private/internal meth­ods, there’s a cou­ple of ques­tions you should always ask your­self first:

  1. The most impor­tant ques­tion of them all is whether or not these meth­ods are even worth test­ing!
  2. If they are worth test­ing, could they be moved into a sep­a­rate class?
  3. Could you cov­er all the test cas­es by mak­ing more calls to the pub­lic meth­ods that call the pri­vate meth­ods?