
How to test non-public methods in .NET
- Tutorial

Well done!
Real professionals do not rely on the case, they
Do you want everything inside, behind the public interface, to be covered with tests?
As always, there are several ways. There is better, there is easier. Go!
1. Making the method public
No private method - no problem. You can also write a comment on the method
// For tests only. Do not use directly.
Pros: very simple.
Cons: the interface is clogged, 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 work here. It turns out a method that is accessible from anywhere within the assembly. And how to test it? Simply. You need to add the InternalsVisibleTo attribute to the assembly . This attribute will give the testing assembly access to all internal methods and properties of the tested assembly.
Do not forget that for the attribute to function
InternalsVisibleTo
it is required that both assemblies (testing and testing) be signed with a strong name at the same time, or not signed at the same time. Pros: simple enough, there remains control over who has access to the insides of the assembly.
Minuses: the interface is still clogged, encapsulation still suffers, additional conditions appear (see above for signing), the attribute remains in the release build.
3. Making the method secure
Instead of a modifier, the
private
method should acquire a modifier protected
. In the testing assembly, you will need to make an inheritor from the tested class and - voila! - Access to the method received. Pros: simple enough, there is some control over who has access to the method.
Cons: the interface is clogged anyway, encapsulation still suffers, the method is accessible to anyone who wants to inherit it, a class with this method cannot be marked as closed for inheritance (sealed).
4. Using PrivateObject
This class provides the Visual Studio Unit Testing Framework , so if the 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 the test is completed, the console will display a line
Don't panic
. Always good advice, right? Pros: no need to change existing code, simple enough.
Cons: applicable only to the Visual Studio Unit Testing Framework, when renaming fields and methods, tests begin to fall.
5. Reflection will help us
The code will be more authentic 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. At least for NUnit, at least for the Visual Studio Unit Testing Framework, at least for any other testing environment.
Pros: no need to change existing code, simple enough, applicable for any test environment.
Cons: without a helper class in the tests there will be kilometers of repeating code, when renaming fields and methods the tests will start to fall.
Instead of a conclusion
Now that you know how to test non-public methods, it's time to think: do they need to be tested?
Arguments for":
- Non-public methods can contain complex logic that is worth checking out.
- Sometimes using private methods in tests can reduce the amount of code needed to create test data.
- Everything needs to be tested. The more lines of code covered by tests, the better.
Arguments against":
- Testing needs behavior, not implementation. So, you need to test only the class interface (only public methods and properties).
- Tests for private methods interfere with code refactoring, and code refactoring is no less important than testing.
- If the method is private, then this is not just. This means that you do not need to touch it.
Personally, I play against the team. I think that only public methods and properties should be tested.
Only registered users can participate in the survey. Please come in.
And what do you think?
- 24% I think that everything needs to be tested. 98
- 55.3% I believe that only public methods and properties should be tested. 226
- 19.1% I don’t write tests at all. 78
- 1.4% I have a different opinion (I will write in the comments). 6