.Net Tips – using InternalsVisibleTo attribute to help testing non-public methods

Yan Cui

I help clients go faster for less using serverless technologies.

Oh, the Pain!

For a long time, unit testing non-public methods in C# has been a pain in the back side. In order to test a non-public method (most likely private methods) you have a number of choices each with an undesired effect:

  1. The easiest way out is to make the methods public. However, this breaks all the encapsulations in your application and can be potentially unsafe because in most cases these methods were not exposed publicly for a reason, e.g. a method which can leave your application in a bad state if used incorrectly.
  2. If making the methods public is a step too far, you can make these methods protected instead and have the unit test class extend this class to gain access to the protected methods. Still, this breaks the encapsulation in your application somewhat, and having a unit test class extend a business logic class ‘smells’. And once again, it can be unsafe as others can also extend your class to gain unintended access to these methods, the same reason why you would often want to seal the LAST type in an inheritance hierarchy – to mark and protect the boundaries of your application.
  3. The last and the most advanced technique is to use reflection to invoke these methods. The upside is that you won’t have to break the encapsulation of your application just to make them testable, the downside is that you pay for this in maintainability and complexity. What it means is that your test class now needs to have intimate knowledge of the class it is testing and because methods names are spelled out in string literals, renaming the non-public method becomes a more costly operation because you need to change all the reflection code used to invoke the method too. Personally this is my least favourite approach as the frequency of change and the number of unit tests in any sizable project can make the task of maintaining them rather unenviable (especially if it’s your job to do so!).

There’s a better way

Since .Net 2.0, you have another alternative thanks to the introduction of the InternalsVisibleTo attribute. It gives you the ability to expose methods marked internal to a specific assembly.

All you need to do is add one line of code to the AssemblyInfo.cs file of the assembly (say, MyApplicatoin) you want to test to allow your unit test assembly (let’s call it MyApplication.Test) to see all the types/methods that have been marked with the internal access modifier:

[assembly: InternalsVisibleTo("MyApplication.Test")]

You will also need to change the access modifier on any methods (in MyApplication) you wish to test to internal for you to be able to see it in MyApplication.Test.

Doing so, however, doesn’t stop you from sealing your type (point 2 above) and doesn’t break all the encapsulation of your application (methods are still inaccessible from external assemblies besides the unit test assembly) although it still breaks the encapsulation of your type because any private methods you wish to test have to be made internal instead and therefore accessible from outside the type.

This is still not ideal, but compared to the alternatives, is still the one that I’m most willing to live with.

Parting thoughts…

Before you jump in with both feet and start testing all the private/internal methods, there’s a couple of questions you should always ask yourself first:

  1. The most important question of them all is whether or not these methods are even worth testing!
  2. If they are worth testing, could they be moved into a separate class?
  3. Could you cover all the test cases by making more calls to the public methods that call the private methods?

 

Whenever you’re ready, here are 4 ways I can help you:

  1. If you want a one-stop shop to help you quickly level up your serverless skills, you should check out my Production-Ready Serverless workshop. Over 20 AWS Heroes & Community Builders have passed through this workshop, plus 1000+ students from the likes of AWS, LEGO, Booking, HBO and Siemens.
  2. If you want to learn how to test serverless applications without all the pain and hassle, you should check out my latest course, Testing Serverless Architectures.
  3. If you’re a manager or founder and want to help your team move faster and build better software, then check out my consulting services.
  4. If you just want to hang out, talk serverless, or ask for help, then you should join my FREE Community.

 


Leave a Comment

Your email address will not be published. Required fields are marked *