How do you test private methods with NUnit?

63,217

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
63,217

Related videos on Youtube

MrFox
Author by

MrFox

Updated on July 08, 2022

Comments

  • MrFox
    MrFox almost 2 years

    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?

  • MrFox
    MrFox over 15 years
    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
    MrFox over 15 years
    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.
  • andy
    andy almost 14 years
    +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
    andy almost 14 years
    + 1 yep! I've just come to that conclusion while writing my tests, good advice!
  • the_joric
    the_joric over 12 years
    @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.
  • Jim D'Angelo
    Jim D'Angelo over 12 years
    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.
  • user1039513
    user1039513 over 12 years
    Could you give an example of having to alter your tests? I don't understand your point.
  • TrueWill
    TrueWill almost 12 years
    It is possible to test internal methods, not private (with NUnit).
  • Johan Larsson
    Johan Larsson over 11 years
    Testing those small helper methods captures the unit part in unit testing. Not all are suitable for utility classes either.
  • Droj
    Droj over 11 years
    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...
  • Quango
    Quango over 11 years
    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.
  • harpo
    harpo over 11 years
    @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.
  • Thomas N
    Thomas N about 11 years
    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.
  • Anders Forsgren
    Anders Forsgren over 10 years
    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.
  • bavaza
    bavaza over 10 years
    This should be the selected answer, as it is the only one which actually answers the question.
  • chesterbr
    chesterbr about 10 years
    Agreed. The chosen answer has its merits, but is the answer to "should I test private methods", not the OP's question.
  • Andrew MacNaughton
    Andrew MacNaughton over 9 years
    thanks @morechilli. Had never seen InternalsVisibleTo before. Made testing much easier.
  • Aleadam
    Aleadam over 9 years
    Hi. Recently received some down votes with no comments. Please provide some feedback to explain your thoughts or concerns.
  • Daniel Macias
    Daniel Macias over 8 years
    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.
  • Aleadam
    Aleadam over 8 years
    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.
  • Able Johnson
    Able Johnson over 8 years
    it works .Thanks! This is what many people are searching for.This should be the selected answer,
  • Gucu112
    Gucu112 over 6 years
    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.
  • Maxim Kitsenko
    Maxim Kitsenko over 6 years
    @Gucu112 Thanks. I fixed it. In general it doesn't matter since the goal is to show aproach from the design pov.
  • Trevor
    Trevor almost 6 years
    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).
  • Kyle Strand
    Kyle Strand over 5 years
    @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".
  • lamont
    lamont over 2 years
    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.
  • Luke
    Luke over 2 years
    NB: There is no package or namespace visibility in C#. The closest thing is internal visibility.