I am wondering how to use NUnit correctly. First, I created a separate test project that uses my main project as reference. But in that case, I am not able to test private m
This question is in its advanced years, but I thought I'd share my way of doing this.
Basically, I have all my unit test classes in the assembly they're testing in a 'UnitTest' namespace below the 'default' for that assembly - each test file is wrapped in a:
#if DEBUG
...test code...
#endif
block, and all of that means that a) it's not being distributed in a release and b) I can use internal
/Friend
level declarations without hoop jumping.
The other thing this offers, more pertinent to this question, is the use of partial
classes, which can be used to create a proxy for testing private methods, so for example to test something like a private method which returns an integer value:
public partial class TheClassBeingTested
{
private int TheMethodToBeTested() { return -1; }
}
in the main classes of the assembly, and the test class:
#if DEBUG
using NUnit.Framework;
public partial class TheClassBeingTested
{
internal int NUnit_TheMethodToBeTested()
{
return TheMethodToBeTested();
}
}
[TestFixture]
public class ClassTests
{
[Test]
public void TestMethod()
{
var tc = new TheClassBeingTested();
Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
}
}
#endif
Obviously, you need to ensure that you don't use this method while developing, though a Release build will soon indicate an inadvertent call to it if you do.
I would make the private methods package visible. That way you keep it reasonably private while still being able to test those methods. I don't agree with the people saying that the public interfaces are the only ones that should be tested. There is often really critical code in the private methods that can't be properly tested by only going through the external interfaces.
So it really boils down to if you care more about correct code or information hiding. I'd say package visibility is a good compromise since in order to access those method someone would have to place their class in your package. That should really make them think twice about whether that is a really smart thing to do.
I'm a Java guy btw, so package visiblilty might be called something entirely different in C#. Suffice to say that it's when two classes have to be in the same namespace in order to access those methods.
A common pattern for writing unit tests is to only test public methods.
If you find that you have many private methods that you want to test, normally this is a sign that you should refactor your code.
It would be wrong to make these methods public on the class where they currently live. That would break the contract that you want that class to have.
It may be correct to move them to a helper class and make them public there. This class may not be exposed by your API.
This way test code is never mixed with your public code.
A similar problem is testing private classes ie. classes you do not export from your assembly. In this case you can explicitly make your test code assembly a friend of the production code assembly using the attribute InternalsVisibleTo.
Generally, unit testing addresses a class's public interface, on the theory that the implementation is immaterial, so long as the results are correct from the client's point of view.
So, NUnit does not provide any mechanism for testing non-public members.
In theory of Unit Testing only contract should be tested. i.e. only public members of the class. But in practice developer usually wants to test internal members to. - and it is not bad. Yes, it goes against the theory, but in practice it can be useful sometimes.
So you if really want to test internal members you can use one of these approaches:
Code example (pseudo code):
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
You can make your methods protected internal, and then using
assembly: InternalsVisibleTo("NAMESPACE")
to your testing namespace.
Hence, NO! You cannot access private methods, but this is a work-around.