How to Test Your Internal Classes in C#

One of the most important concepts of object-oriented design is encapsulation. You try to hide all the internal things of a class from the other developers and only offer them a subset of functionality to use. You can achieve this by setting an appropriate access modifier for your methods and classes:

  • public: The type or member can be accessed by any other code in the same assembly or another assembly that references it.
  • private: The type or member can be accessed only by code in the same class or struct.
  • protected: The type or member can be accessed only by code in the same class, or in a class that is derived from that class.
  • internal: The type or member can be accessed by any code in the same assembly, but not from another assembly.
  • protected internal: The type or member can be accessed by any code in the assembly in which it is declared, or from within a derived class in another assembly. (as in protected OR internal)
  • private protected: The type or member can be accessed only within its declaring assembly, by code in the same class or in a type that is derived from that class. (as in private OR protected)

Public and private are the two most used access modifiers. You find them in all the examples, they are straight forward to use and do exactly what you expect. They are a great help to manage access to the methods in your classes and the classes themselves.

If we look at bigger parts of our application, we use code from different assemblies or NuGet packages. Those distribution formats have their own boundaries that you can use to enforce encapsulation. Public and private access modifiers are again a great help. However, over the years I appreciated the internal access modifier more and more.

 

Benefits of the internal access modifier

There is always that code that you need but has no place to go. It is not a class on its own and it does not fit to any other. At some point you stop searching for the right place and put it into a class called MyHelper. That code can’t be private, then many of your classes need them. And you do not want to make it public, then this code should not be called from outside your assembly.

The internal access modifier is exactly made for such use cases. By declaring the class or just a few methods as internal, you can access them from everywhere in your assembly but not from outside. All you need to do is to write internal instead of public or private:

The users of your assembly or NuGet package do not know that this helper method exist. That allows you to freely move that code around to a better location or refactor it until you find a more fitting abstraction. All that without the need to change code outside your assembly – then no one else can call it directly.

internal code cannot be seen outside of assembly

 

How to test internal methods and classes?

That helper code you marked with internal is most often important. Therefore, you should write extensive tests for those classes and methods. But how can you do that when you can’t access that code from outside your assembly?

The .NET Framework offers the InternalsVisibleTo attribute to specify which other assemblies can access the internal methods and classes inside this assembly. All you need to do is to add this attribute to the AssemblyInfo.cs file and pass the name of your test assembly to the constructor:

When you put this attribute to the AssemblyInfo.cs file, then all internal methods can be accessed by code inside the Logic.Tests assembly. To test your internal code this behaviour is exactly what you want.
If this is too much, you can add this attribute in a specific class and only allow access to the internal methods of this class.

As soon as you recompile your assembly, the code in your test assembly can access your internal methods:

test code can now see internal method

 

.Net Core

In .Net Core you do not have an AssemblyInfo.cs file. You can add one with the Add New Item dialog and set the attribute there in the same way you would do that in the .Net Full Framework and get exactly the same benefits.

add AssemblyInfo.cs via New Item dialog

 

.Net Standard project

As pointed out by Miguel Alho in the comments, you can add an ItemGroup in your *.csproj file to get the same effect. For that, paste this code as the last block before the closing project tag:

 

Conclusion

Use the internal access modifier the next time you have helper code that you need but no one else should call. This little keyword will help you to hide your mess inside your assembly and still allows you to write tests. With internal you get the best of both worlds without breaking encapsulation.

 
Updates:

  • 2020-01-17: add example for .Net Standard project

3 thoughts on “How to Test Your Internal Classes in C#”

    • Hi Miguel,
      Thanks for your input. Your comment was a great help for me today as I had to work with a .Net Standard project.

      Regards,
      Johnny

      Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.