How do you test private methods with NUnit?

≯℡__Kan透↙ 提交于 2019-12-17 10:35:11

问题


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 testcode 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?


回答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.




回答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.




回答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.




回答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.




回答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.




回答6:


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.




回答7:


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.




回答8:


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.




回答9:


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.




回答10:


You can make your methods protected internal, and then using assembly: InternalVisibleTo("NAMESPACE") to your testing namespace.

Hence, NO! You cannot access private methods, but this is a work-around.




回答11:


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:

  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 assebly
  3. You can make class members protected and inherit your test class from your under testing class.

Code example (pseudo code):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}



回答12:


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.



来源:https://stackoverflow.com/questions/249847/how-do-you-test-private-methods-with-nunit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!