📜 ⬆️ ⬇️

How to test non-public methods in .NET

image Do you like to cover code with tests? Do you like the pleasant warm feeling of security that comes with passing tests?

Well done!

Real professionals do not rely on chance, they lay straws in advance and keep everything under control.
')
Want to inside, for the public interface, too, everything was covered in tests?



As always, there are several ways. There are better, there are easier. Go!

1. Making the method public


No private method - no problem. You can even write a comment to the method

// For tests only. Do not use directly. 


Pros: very simple.
Minuses: the interface is littered, encapsulation suffers.

2. Making the method internal


That is, we change the access modifier from private to internal . The comment from the first method will also fit here. It turns out a method that is available from anywhere within the assembly.

And test it as? Simply. You need to add the InternalsVisibleTo attribute to the assembly. This attribute will give the test assembly access to all internal methods and properties of the assembly under test.

Do not forget that the functioning of the InternalsVisibleTo attribute requires that both assemblies (testing and tested) be signed with a strong name at the same time, or not signed at the same time.

Pros: simply enough, there remains control over who has access to the interiors of the assembly.
Minuses: the interface is still clogged, encapsulation still suffers, additional conditions appear (see above about signing), the attribute remains in the release build.

3. Making the method protected


Instead of the private modifier, the method should acquire the protected modifier. In the test build, you will need to make an inheritor from the class under test and - voila! - access to the method obtained.

Pros: simple enough, there is some control over who has access to the method.
Minuses: the interface is still clogged, encapsulation still suffers, the method is available to anyone who wishes to inherit it, a class with this method cannot be marked closed for inheritance (sealed).

4. Use PrivateObject


This class provides the Visual Studio Unit Testing Framework , so if a project uses NUnit or something else, then this method will not work.

With PrivateObject everything is simple. There is a class for testing:

 public class ClassToTest { private string field; private void PrintField() { Console.WriteLine(field); } } 


There is a testing class:

 [TestClass] public class TestClass { [TestMethod] public void TestPrivateMethod() { ClassToTest testedClass = new ClassToTest(); PrivateObject privateObject = new PrivateObject(testedClass); privateObject.SetField("field", "Don't panic"); privateObject.Invoke("PrintField"); } } 


After executing the test in the console, the string will Don't panic . Always good advice, right?

Pros: you do not need to change the existing code, quite simply.
Disadvantages: applicable only to the Visual Studio Unit Testing Framework, when renaming fields and methods, the tests will start to fall.

5. Reflection will help us


The code will be longer than in the previous method, but you can live.

Again, there is a class for testing:

 public class ClassToTest { private string field; private void PrintField() { Console.WriteLine(field); } } 


In the test you need to write the following:

 ClassToTest obj = new ClassToTest(); Type t = typeof(ClassToTest); FieldInfo f = t.GetField("field", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); f.SetValue(obj, "Don't panic"); t.InvokeMember("PrintField", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, obj, null); 


Good advice should appear in the console again.

The above code can be used in any tests. Though for NUnit, at least for the Visual Studio Unit Testing Framework, at least for any other testing environment.

Pros: there is no need to change the existing code, quite simply, applicable to any testing environment.
Minuses: without the auxiliary class in the tests there will be kilometers of the repeating code, when renaming the fields and methods, the tests will start to fall.

Instead of conclusion


Now that you know how to test non-public methods, it's time to think: should we test them?

Arguments for":


Arguments against":


Personally, I play for the team "against." I think that you only need to test public methods and properties.

Source: https://habr.com/ru/post/224733/


All Articles