Reputation: 42749
I am currently testing private method this way (using nunit
):
class Foo
{
private int Identity(int n) => n;
}
[TestFixture]
class MyTests
{
[Test]
public void TestFoo()
{
var myFoo = new Foo();
var identityMethod = myFoo.GetType().GetMethod("Identity", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.That(identityMethod.Invoke(myFoo, new []{ (object)42 }), Is.EqualTo(42));
}
}
My team does not like this, because put the method name as a string prevent this method to be renamed, if we want to do refactoring through automatic tools.
I tried to replace the name with nameof
, but:
Foo.Indentity(int) is inaccessible due to its protection level
(By the way, this is strange in my opinion that such an operator respects the privacy protections).
So, can I test private methods without sacrificing possible refactoring?
I was proposed to make the private methods protected and inherit the class with the class test, but this does not satisfy me.
Disclaimer: I know that some people think that private method should not be tested, but this is not the point here. Please do not transform this question into a debate about this.
Upvotes: 0
Views: 405
Reputation: 13681
Putting on my coach hat on top of my testing software hat...
The warning to not test private methods is often misunderstood. I like to say consider the difficulty of testing private methods as a warning that something is wrong with the overall design.
Information hiding and testability are both characteristics of a good design. They are, unfortunately, sometimes in conflict and as with many other things you have to use your judgement to strike a balance. Since they are both goals of the design, there is no absolute answer like "Don't test the private methods" or "Don't make any methods private." You have to decide for yourself.
Often, a private method that we feel a strong need to test is a sign of a problem with the design. Maybe it should be protected. Maybe it actually represents a need for a new class, which you can test separately. I don't know, of course, since I don't know the actual code.
All this assumes that you have control over the design. If not - if you are only responsible for the tests - then you can either not test those methods or the responsible people can do something to make it possible for you to test them. Using InternalsVisibleTo
with an internal
method is a pretty good compromise a lot of the time.
Upvotes: 2
Reputation: 37000
There´s no way to ensure your code won´t break because of a private member being renamed. Even nameof
won´t help as you already mentioned because it can´t access private members. That´s one of the reasons you shouldn´t test private members - at least not directly but instead through your public API.
The only thing you could do is make your member internal
and mark your assembly as InternalsVisibleTo
combined with the name of your test-assembly. This way all internals are visible to your test-project. Be aware that doing so on a signed assembly will make indicate the fully qualified name of the friend-assembly.
Upvotes: 2