Testing non-public methods from another project
I had a few methods in a project that implemented some business logic that I wanted to be able to test from another project, but that weren't public. So how can I test them? Well...
A testable method should be relatively self-contained. It should take a set of inputs and return any outputs without requiring or mutating any additional "global" state, so that you're testing just the behaviour of that method.
You need to be able to call the method. This is easy if the method is static
, or if it's on a public class that's easy to instantiate (i.e. no huge amount of build-up or tear-down should be required).
The method you're testing needs to be visible to your test project. What access modifier would let me make these already-static methods visible only within the main project and my test project?
- These methods weren't
public
, and had no reason to be. They shouldn't be called from anything outside that project (except tests!) - A
private
method is inaccessible. - A
protected
method on a public class would give me the ability to create a derived test class that would inherit from the base class, and would thus have access to the method... but that's too clunky. protected internal
- also not quite right, similar to 'protected' in this instance.internal
which would allow them to be "accessed by any code in the same assembly, but not from another assembly".
Luckily internal
(Friend
in Visual Basic) works with the InternalsVisibleTo attribute to allow you to specify a set of other assemblies which are allowed to access internal
methods. This was as simple as adding a declaration to my main project - which I put in to AssemblyInfo.cs:
[assembly:InternalsVisibleTo("My.Test.Project")]
Now, My.Test.Project can call the internal methods declared in my main project without requiring me to make these methods visible to the entire world.
This gets a little bit trickier if you're using signed assemblies as you have to include the public key - but this is documented on the InternalsVisibleTo attribute MSDN page.