Secure Unit Testing and Signed Assemblies
When looking at examples for unit testing you'll typically see that all the methods for the class under test are public. Either that, or that the unit tests themselves are in the same class assembly as the class under test.
The first pattern (all public methods) represents a problem when you don't want every method to be public, especially if you need to distribute your assembly far and wide where it will live outside of your control. All those public methods are a great way for people to attack or misuse your application.
The second method (embed unit tests) is probably worse, since you're then not only distributing your code, but all your tests as well. All those unit tests themselves can be used as an attack vector for your application.
Does this mean that if you secure your methods using the internal attribute that you can't unit test them? Not at all!
What you need to do is give permissions to allow the unit test assembly to see the internal methods of your classes using the InternalsVisibleTo assembly attribute (.NET 2.0+).
Let's say we have an assembly called BusinessLogic.DLL with a class MyClass as follows:
internal class MyClass
{
internal int MyMethod()
{
//... Do Stuff
}
}
And we now want to create a unit test for this class in a separate BusinessLogicTests.DLL like so:
[TestFixture()]
public class MyClassTests
{
[TestMethod()]
public void TestMyMethod()
{
MyClass myClass = new MyClass();
Assert.AreEqual(myClass.MyMethod(), 0);
}
}
Then we would have a problem, as MyClass is not visible to MyClassTests because of the internal permission.
To resolve this we can get the BusinessLogic.DLL to explicitly give permissions to the BusinessLogicTests.DLL to see it's internal classes and methods.
By adding the following to the assemblyinfo.cs file in BusinessLogic.DLL
[assembly: InternalsVisibleTo("BusinessLogicTests")]
We explicitly give permissions for the BusinessLogicTests assembly to see the internal members which now gives us the ability to write our unit tests as we wish without exposing our methods and classes for the whole world to see.
Signed Assemblies
There is one wrinkle though. If we need to sign the BusinessLogic.DLL assembly then we also need to sign the BusinessLogicTests.DLL so that we can reference the assembly under test at run time (or we get runtime security errors). However once we do this the InternalsVisibleTo line shown above will no longer work, as we need to include the public key of the unit test assembly.
So, how do we get the public key for our unit tests? Assuming your strong name key for the unit tests is called UnitTestKey.snk then you can do the following from the command prompt:
1. Run sn.exe -p UnitTestKey.snk UnitTestKey.PublicKey. This will extract the public key to a file with the .PublicKey extension.
2. Run sn.exe -tp UnitTestKey.PublicKey. This will display the public key for you, which will be a big long string of hexadecimal. Copy this key.
3. Paste it into in your code (and remove the line breaks) as
[assembly: InternalsVisibleTo("BusinessLogicTests, PublicKey=<<PASTE-YOUR-PUBLIC-KEY-HERE>>")]
Once you've done this your code should look like this:
[assembly: InternalsVisibleTo("BusinessLogicTests, PublicKey=01440204048000009400000006020000002400005253416100040000f1000100971adbbcba6b77844f73323f234c918f421b7472af8e6d61e7e164180f226d0c6592cfad83153a790d10310abc338632208a775d588f7e0302d498a8506f2fcaa78d6c20d5220db75c802309ae8c30d3c7532e8055f55ab122a90bda7aaab82481674a9343eedb1784d1fedf4653c733885412a97fdd88cc89bd3376f870949b")]
After this you should be able to compile and run your unit tests without a problem, and without exposing anything you shouldn't to the outside world.