Unit Test Non-Public Methods and Classes

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):

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" +

2 thoughts on “Unit Test Non-Public Methods and Classes

  1. Niklas,

    I think it is a balance between two things that don’t feel right, the first making private methods internal vs true unit tests. I tend to break my methods down into as many small methods as possible and I prefer to unit test those smaller methods on their own and write them in a TDD style. I find that I drift into a tendency to write fewer tests if I only test through the public methods because of the additional setup for each test. I also feel that these larger tests start leaning towards the integration test end of the scale. I think those are necessary too, but prefer smaller, more succinct unit tests too.

    I would also argue that we have a tendency to make too much public. Take a look at most projects and I think you will find the majority of classes are public (if not all). How many of those classes are ever called from outside the assembly they are declared in? Shouldn’t they be internal?

    This has actually become a problem for us developing NUnit. We have public classes that are intended to be used when writing tests and public APIs that are intended to be consumed by 3rdParty developers. For testing however, most of our classes are public and we have many issues reported where people are using these classes incorrectly where we didn’t intend them to be used externally. We have started making those classes internal to prevent incorrect use. It also has the advantage of reducing the number of classes that show up in Intellisense.

    To sum up, I don’t think we should dismiss something out of hand because it offends our sense of purity. If making a method internal instead of private makes our code or our tests easier to write, read, consume and understand, then go for it. Evaluate and decide if the code is better or worse 🙂


  2. Hi Rob,

    I used to do this a while back ago as well but I’ve realized that it just doesn’t feel right.
    My common scenario was that I adapted my methods from being private to internal to be able to test them.
    Nowadays I strive to test them through the public API instead. I am interesting if you have any use cases where you cannot cover the private methods by testing the public API?


Comments are closed.