Unit Test Non-Public Methods and Classes

2017, Jan 09    

You often want to unit test non-public methods and classes in .NET, but you don't want to make them public. The most common solution is to make the methods and classes internal and access them from your unit test project using the InternalsVisibleTo attribute.

Unsigned Assemblies

If your assemblies are unsigned, edit AssemblyInfo.cs in the project you are unit testing and add the following attribute,

[assembly: InternalsVisibleTo("MyAssembly.Tests")]

Remember to add the attribute to your main project and use the name of your test project. Once you do this, you can access internal classes and methods from your test project.

Signed Assemblies

If your assemblies are signed, you must sign your test assembly and include the full public key in the InternalsVisibleTo attribute.

To do this, use the Strong Name Tool (sn.exe) to extract the public key from your test assembly.

  1. Open a Visual Studio command prompt
  2. CD to the bin directory where your test assembly was built
  3. Run the command sn -Tp MyAssembly.Tests

Running this command will produce the following output,

Microsoft (R) .NET Framework Strong Name Utility  Version 4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key (hash algorithm: sha1):
0024000004800000940000000602000000240000525341310004000001000100750098646d1c04
c2a041faaf801521a769535de9a04cd3b4dedccbf73d1a6456bf4fe58814510e84983c72d0460b
8ba85c52a9cacdc4a0786af54e90cb7a81eb2049ecfe6b2c5e20a18fe4b9bff009ada232e980d2
20b3c9586c9c5ee29c29aee8853db7bb90cf5a4c704f5244e1a1085c43060085350329021ec902
47e70eb2

Public key token is a5778f560690a058

Copy the full public key and add it to the InternalsVisibleTo attribute in AssemblyInfo.cs

[assembly: InternalsVisibleTo("MyAssembly.Tests, PublicKey=" +
            "0024000004800000940000000602000000240000525341310004000001000100750098646d1c04" +
            "c2a041faaf801521a769535de9a04cd3b4dedccbf73d1a6456bf4fe58814510e84983c72d0460b" +
            "8ba85c52a9cacdc4a0786af54e90cb7a81eb2049ecfe6b2c5e20a18fe4b9bff009ada232e980d2" +
            "20b3c9586c9c5ee29c29aee8853db7bb90cf5a4c704f5244e1a1085c43060085350329021ec902" +
            "47e70eb2")]