C# 如何使用 NUnit 测试私有方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/249847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:54:24  来源:igfitidea点击:

How do you test private methods with NUnit?

c#unit-testingtestingnunit

提问by MrFox

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.)

我想知道如何正确使用 NUnit。首先,我创建了一个单独的测试项目,使用我的主项目作为参考。但在那种情况下,我无法测试私有方法。我的猜测是我需要将我的测试代码包含在我的主代码中?!- 这似乎不是正确的做法。(我不喜欢发布带有测试的代码的想法。)

How do you test private methods with NUnit?

如何使用 NUnit 测试私有方法?

采纳答案by harpo

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.

因此,NUnit 不提供任何测试非公共成员的机制。

回答by Maxime Rouiller

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.

单元测试的主要目标是测试类的公共方法。那些公共方法将使用那些私有方法。单元测试将测试公开可用的行为。

回答by Tigraine

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).

如果您有一些内部方法和属性,您应该考虑将其更改为 public,或者将您的测试与应用程序一起发送(我认为这不是问题)。

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.

如果您的客户能够运行测试套件并看到您提供的代码实际上“有效”,我认为这不是问题(只要您不通过此方式泄露您的 IP)。我在每个版本中包含的内容是测试报告和代码覆盖率报告。

回答by morechilli

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.

将它们移动到辅助类并在那里公开它们可能是正确的。您的 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.

一个类似的问题是测试私有类,即。不从程序集中导出的类。在这种情况下,您可以使用 InternalsVisibleTo 属性显式地使您的测试代码程序集成为生产代码程序集的朋友。

回答by Fylke

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.

顺便说一句,我是一个 Java 人,所以包可见性在 C# 中可能被称为完全不同的东西。可以说,当两个类必须在同一个命名空间中才能访问这些方法时就足够了。

回答by Dafydd Giddins

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

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.

如果您仍然觉得需要进行内部测试,那么您可能还需要考虑在测试中进行模拟,因为您可能希望专注于一段代码。模拟是您将对象依赖项注入其中但注入的对象不是“真实”或生产对象的地方。它们是具有硬编码行为的虚拟对象,可以更轻松地隔离行为错误。Rhino.Mocks 是一个流行的免费模拟框架,它基本上会为您编写对象。TypeMock.NET(具有社区版的商业产品)是一个更强大的框架,可以模拟 CLR 对象。例如在测试数据库应用程序时模拟 SqlConnection/SqlCommand 和 Datatable 类非常有用。

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.

希望这个答案会给你更多的信息,让你了解一般的单元测试,并帮助你从单元测试中获得更好的结果。

回答by Ritesh

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.

抱歉,如果这不能回答问题,但使用反射、#if #endif 语句或使私有方法可见等解决方案并不能解决问题。不使私有方法可见可能有几个原因……例如,如果它是生产代码并且团队正在追溯编写单元测试怎么办。

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

对于我正在处理的项目,只有 MSTest(遗憾的是)似乎有办法使用访问器来对私有方法进行单元测试。

回答by user1039513

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:

虽然我同意单元测试的重点应该是公共接口,但如果您也测试私有方法,您会对代码有更细致的印象。MS 测试框架通过使用 PrivateObject 和 PrivateType 来实现这一点,而 NUnit 则不允许。我做的是:

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.

这种方式意味着您不必为了可测试性而妥协封装。请记住,如果要测试私有静态方法,则需要修改 BindingFlags。上面的例子只是实例方法。

回答by Mark Glass

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.

我赞成有能力测试私有方法。当 xUnit 启动时,它用于在编写代码后测试功能。为此目的,测试接口就足够了。

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

单元测试已经演变为测试驱动的开发。能够测试所有方法对于该应用程序很有用。

回答by Stuart Wood

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:

基本上,我在程序集中有我所有的单元测试类,它们在该程序集的“默认”下方的“UnitTest”命名空间中进行测试 - 每个测试文件都包装在:

#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/Friendlevel declarations without hoop jumping.

块,所有这一切都意味着 a) 它不会在发布中分发,并且 b) 我可以使用internal/ Friendlevel 声明而无需跳箍。

The other thing this offers, more pertinent to this question, is the use of partialclasses, 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:

这提供的另一件事与这个问题更相关,是使用partial类,它可用于创建用于测试私有方法的代理,例如测试诸如返回整数值的私有方法之类的东西:

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.

显然,您需要确保在开发时不使用此方法,尽管如果您这样做,Release 构建很快就会指示对它的无意调用。