123

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 methods. My guess was that I need to include my test code into my main code?! - That doesn't seem to be the correct way to do it. (I dislike the idea of shipping code with tests in it.)

How do you test private methods with NUnit?

Pang
  • 9,564
  • 146
  • 81
  • 122
MrFox
  • 3,233
  • 6
  • 25
  • 27

13 Answers13

77

While I agree that the focus of unit testing should be the public interface, you get a far more granular impression of your code if you test private methods as well. The MS testing framework allows for this through the use of PrivateObject and PrivateType, NUnit does not. What I do instead is:

private MethodInfo GetMethod(string methodName)
{
    if (string.IsNullOrWhiteSpace(methodName))
        Assert.Fail("methodName cannot be null or whitespace");

    var method = this.objectUnderTest.GetType()
        .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

    if (method == null)
        Assert.Fail(string.Format("{0} method not found", methodName));

    return method;
}

This way means you don't have to compromise encapsulation in favour of testability. Bear in mind you'll need to modify your BindingFlags if you want to test private static methods. The above example is just for instance methods.

user1039513
  • 812
  • 6
  • 5
  • 1
    By testing private methods, it seems you are making it harder to complete the whole TDD cycle: red->green->refactor. If I have to keep altering my tests to refactor, I am wasting time and I'm not sure I would be able to really trust those tests. I know not everybody who writes unit tests uses TDD, but you're still causing more pain when you need to refactor. – Jim D'Angelo Jan 27 '12 at 15:34
  • Could you give an example of having to alter your tests? I don't understand your point. – user1039513 Jan 30 '12 at 07:15
  • 7
    Testing those small helper methods captures the unit part in unit testing. Not all are suitable for utility classes either. – Johan Larsson Sep 27 '12 at 22:38
  • 14
    This is exactly what I needed. Thanks! All I needed was to check that a private field was getting set properly, and I DIDN'T need to spend 3 hours to figure out how to determine that via the public interface. This is existing code that can't be refactored on a whim. It's funny how a simple question can be answered with idealistic dogma... – Droj Nov 09 '12 at 20:11
  • 6
    This should be the selected answer, as it is the only one which actually answers the question. – bavaza Dec 10 '13 at 16:04
  • 7
    Agreed. The chosen answer has its merits, but is the answer to "should I test private methods", not the OP's question. – chesterbr Mar 13 '14 at 17:25
  • 3
    it works .Thanks! This is what many people are searching for.This should be the selected answer, – Able Johnson Feb 02 '16 at 10:29
74

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.

harpo
  • 41,820
  • 13
  • 96
  • 131
  • You are completly right. If there is some private logic that urgently needs to be tested (because of frequnet bugs), then I sould think about decompositions rather than testing inner circuits. – MrFox Oct 30 '08 at 11:42
  • 1
    +1 I've just come up against this issue and in my case there's a "mapping" algorithm that happens in between the private and the public meaning if I were to Unit Test the public, it would actually be an integration test. In this scenario I think it trying to write the test points to a design problem in the code. in which case I should probably create a different class which performs that "private" method. – andy Jul 19 '10 at 02:34
  • @MrFox actually all private logic is exposed to outer world by public methods, so eventually you can cover all it via tests for public API of your class. However decoupling might be better option if private logic is adding too much cyclomatic complexity to your class. – the_joric Dec 21 '11 at 09:04
  • 161
    I disagree completely with this argument. Unit testing is not about the class, it's about the *code*. If I had a class with one public method, and ten private ones used to create the result of the public one, I have no way of ensuring each private method works in the intended way. I could try to create test cases on the public method that hit the right private method in the right way. But I then have no idea whether the private method was actually called, unless I trust the public method to never change. Private methods are intended to be private to production users of code, not the author. – Quango Jan 17 '13 at 12:10
  • 3
    @Quango, in a standard testing setup, the "author" *is* a production user of the code. Nevertheless, if you don't smell a design problem, you have options for testing non-public methods without altering the class. `System.Reflection` allows you to access and invoke non-public methods using binding flags, so you could hack NUnit or set up your own framework. Or (easier, I think), you could set up a compile-time flag (#if TESTING) to change the access modifiers, allowing you to use existing frameworks. – harpo Jan 17 '13 at 16:09
  • 25
    A private method is an implementation detail. A lot of the point of having unit tests is to allow for refactoring of the *implementation* without changing the *behavior*. If private methods become so complicated that one would like to cover them with tests individually, then this lemma can be used: "A private method can always be a public (or internal) method of a separate class". That is, if a piece of logic is sufficiently advanced to be subject to testing, it is probably candidate for being its own class, with its own tests. – Anders Forsgren Oct 22 '13 at 13:05
  • 7
    @AndersForsgren But the point of _unit_ testing, as opposed to _integration_ or _functional_ testing, is precisely to test such details. And code-coverage is considered an important unit-testing metric, so in theory _every_ piece of logic is "sufficiently advanced to be subject to testing". – Kyle Strand Jan 30 '19 at 18:21
  • 1
    re: "A private method can always be a public (or internal) method of a separate class". If you change it to public then someone can call it externally and depend upon it and it is no longer an implementation detail. You can't change its behavior without modifying a public API, so the approach is no longer remotely equivalent under encapsulation. But sometimes it is important to test and get the implementation details correct since testing the composition of something which is very complicated doesn't always guarantee that the edge cases of the subcomponents are sufficiently explored. – lamont Feb 04 '22 at 05:29
51

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.

morechilli
  • 9,827
  • 7
  • 33
  • 54
  • 1
    + 1 yep! I've just come to that conclusion while writing my tests, good advice! – andy Jul 19 '10 at 02:35
  • 1
    Moving private methods that you want to test but not expose to users of the API to a different class that is not exposed and make them public there is exactly what I was looking for. – Thomas N Apr 09 '13 at 07:31
  • thanks @morechilli. Had never seen InternalsVisibleTo before. Made testing much easier. – Andrew MacNaughton Oct 30 '14 at 19:59
  • Hi. Recently received some down votes with no comments. Please provide some feedback to explain your thoughts or concerns. – morechilli Feb 12 '15 at 12:47
  • 9
    So if you have a private method that's being called in multiple places within a class to do something very specific only needed by that class and it's not to be exposed as part of the public API... you're saying put it in a helper class just to test? You might as well just make it public for the class. – Daniel Macias Oct 21 '15 at 03:24
  • It's been 7 years since I wrote this answer...looking at it now I would say that statefulness is another interesting consideration. An alternative to moving the method to a helper class would be to ensure that the method is static thus removing it's ability to mutate state in the object and therefore maybe removing the concerns about making it public (often the move to the helper class would have led to this same change). Then the decision becomes one of cleanliness for the API. – morechilli Oct 21 '15 at 10:40
  • Good answer this is how I would deal with a brown field project where there are no tests and you can't yet back the code with a unit test because of this scenario so start refactoring, move code into a public method in a helper class and back that class with an interface if you need to for DI. This can then be tested (I like nunit here). – Trevor May 25 '18 at 02:32
22

It is possible to test private methods by declaring your test assembly as a friend assembly of the target assembly you are testing. See the link below for details:

http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

This can be useful as it does mostly seperate your test code from your production code. I have never used this method myself as i have never found a need for it. I suppose that you could use it to try and test extreme test cases which you simply can't replicate in your test environment to see how your code handles it.

As has been said though, you really shouldn't need to test private methods. You more than likley want to refactor your code into smaller building blocks. One tip that might help you when you come to refactor is to try and think about the domain that your system relates to and think about the 'real' objects that inhabit this domain. Your objects/classes in your system should relate directly to a real object which will allow you to isolate the exact behaviour that the object should contain and also limit the objects responsibilities. This will mean that you are refactoring logically rather than just to make it possible to test a particular method; you will be able to test the objects behaviour.

If you still feel the need to test internal then you might also want to consider mocking in your testing as you are likley to want to focus on one piece of code. Mocking is where you inject an objects dependencies into it but the objects injected are not the 'real' or production objects. They are dummy objects with hardcoded behaviour to make it easier to isolate behavioural errors. Rhino.Mocks is a popular free mocking framework which will essentially write the objects for you. TypeMock.NET (a commercial product with a community edition available) is a more powerful framework which can mock CLR objects. Very useful for mocking the SqlConnection/SqlCommand and Datatable classes for instance when testing a database app.

Hopefully this answer will give you a bit more information to inform you about Unit Testing in general and help you get better results from Unit Testing.

Ben
  • 1,321
  • 15
  • 30
Dafydd Giddins
  • 2,276
  • 3
  • 24
  • 31
6

I'm in favor of having the capability to test private methods. When xUnit started it was intended for testing functionality after the code was written. Testing the interface is sufficient for this purpose.

Unit testing has evolved to test-driven development. Having the capability to test all methods is useful for that application.

Mark Glass
  • 386
  • 1
  • 7
  • 15
5

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.

Stuart Wood
  • 196
  • 1
  • 5
4

The main goal of unit testing is to test the public methods of a class. Those public methods will use those private methods. Unit testing will test the behavior of what is publicly available.

Maxime Rouiller
  • 13,614
  • 9
  • 57
  • 107
3

Apologies if this doesn't answer the question but solutions like using reflection, #if #endif statements or making private methods visible does not solve the problem. There can be several reasons for not making private methods visible... what if it's production code and the team is retrospectively writing unit tests for example.

For the project that I am working on only MSTest (sadly) appears to have a way, using accessors, to unit test private methods.

Ritesh
  • 161
  • 1
  • 4
2

You don't test private functions. There are ways to use reflection to get into private methods and properties. But that isn't really easy and I strongly discourage this practice.

You simply shouldn't test anything that's not public.

If you have some internal methods and properties, you should consider either changing that to public, or to ship your tests with the app (something I don't really see as a problem).

If your customer is able to run a Test-Suite and see that the code you delivered is actually "working", I don't see this as a problem (as long as you don't give away your IP through this). Things I include in every release are test-reports and code coverage reports.

Tigraine
  • 23,358
  • 11
  • 65
  • 110
  • Some customers try to keep the budget small and start discussions on the scope of tests. It's hard to explain these people that writing test is not because you are a bad coder and do not trust your own skills. – MrFox Oct 30 '08 at 11:52
2

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 too - and it is not bad. Yes, it goes against the theory, but in practice it can be useful sometimes.

So if you really want to test internal members, you can use one of these approaches:

  1. Make your member public. In many books, authors suggest this approach as simple
  2. You can make you members internal and add InternalVisibleTo to assembly
  3. You can make class members protected and inherit your test class from your class under test.

Code example (pseudo code):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
    
    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Maxim Kitsenko
  • 2,042
  • 1
  • 20
  • 43
  • Seems that cockroach is hidden inside your example code ;) Method inside NUnit's fixture must be public, otherwise you get `Message: Method is not public`. – Gucu112 Nov 25 '17 at 12:16
  • @Gucu112 Thanks. I fixed it. In general it doesn't matter since the goal is to show aproach from the design pov. – Maxim Kitsenko Nov 27 '17 at 12:37
1

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.

Xavier Egea
  • 4,712
  • 3
  • 25
  • 39
1

If you need to access a non-static private method of class, could try this:

class Foo 
{
    private int Sum(int num1, int num2)
    {
        return num1 + num2;
    }
}
MethodInfo sumPrivate = 
    typeof(Foo).GetMethod("Sum", BindingFlags.NonPublic | BindingFlags.Instance);

int sum = (int)sumPrivate.Invoke(new Foo(), new object[] { 2, 5 });
// 7
Rohim Chou
  • 907
  • 10
  • 16
0

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.

Fylke
  • 1,753
  • 3
  • 19
  • 30
  • NB: There is no package or namespace visibility in C#. The closest thing is internal visibility. – Luke Feb 08 '22 at 16:25