如何使用 NUnit 测试私有方法?
我想知道如何正确使用 NUnit。 首先,我创建了一个单独的测试项目,使用我的主项目作为参考。 但在这种情况下,我无法测试私有方法。 我的猜测是我需要将测试代码包含到我的主代码中?! - 这似乎不是正确的方法。 (我不喜欢在代码中包含测试的想法。)
如何使用 NUnit 测试私有方法?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
虽然我同意单元测试的重点应该是公共接口,但如果您也测试私有方法,您会对代码有更精细的印象。 MS 测试框架允许通过使用 PrivateObject 和 PrivateType 实现这一点,而 NUnit 则不允许。 我所做的是:
这种方式意味着您不必为了可测试性而牺牲封装性。 请记住,如果您想测试私有静态方法,则需要修改 BindingFlags。 上面的例子只是示例方法。
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:
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.
一般来说,单元测试针对类的公共接口,其理论是实现并不重要,只要从客户端的角度来看结果是正确的。
因此,NUnit 不提供任何测试非公共成员的机制。
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.
编写单元测试的常见模式是仅测试公共方法。
如果您发现有许多想要测试的私有方法,通常这表明您应该重构代码。
将这些方法在它们当前所在的类中公开是错误的。
这会破坏你希望该类拥有的合同。
将它们移至辅助类并在那里公开它们可能是正确的。
您的 API 可能不会公开此类。
这样测试代码永远不会与您的公共代码混合。
类似的问题是测试私有类,即。 您不从程序集中导出的类。
在这种情况下,您可以使用属性InternalsVisibleTo 显式地使测试代码程序集成为生产代码程序集的友元。
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.
通过将测试程序集声明为正在测试的目标程序集的友元程序集,可以测试私有方法。 有关详细信息,请参阅下面的链接:
http://msdn.microsoft.com/en- us/library/0tke9fxk.aspx
这可能很有用,因为它主要将测试代码与生产代码分开。 我自己从未使用过这种方法,因为我从未发现需要它。 我想您可以使用它来尝试和测试极端的测试用例,而您根本无法在测试环境中复制这些测试用例来查看代码如何处理它。
正如已经说过的,您确实不需要测试私有方法。 您非常希望将代码重构为更小的构建块。 当您进行重构时,一个可能对您有所帮助的技巧是尝试考虑与您的系统相关的域,并考虑居住在该域中的“真实”对象。 系统中的对象/类应该与真实对象直接相关,这将允许您隔离对象应包含的确切行为,并限制对象的职责。 这意味着您正在逻辑上重构,而不仅仅是为了测试特定方法; 您将能够测试对象的行为。
如果您仍然觉得需要测试内部,那么您可能还需要考虑在测试中进行模拟,因为您可能希望专注于一段代码。 模拟是指将对象依赖项注入其中,但注入的对象不是“真实”或生产对象。 它们是具有硬编码行为的虚拟对象,可以更轻松地隔离行为错误。 Rhino.Mocks 是一个流行的免费模拟框架,它本质上会为您编写对象。 TypeMock.NET(具有社区版本的商业产品)是一个更强大的框架,可以模拟 CLR 对象。 对于模拟 SqlConnection/SqlCommand 和 Datatable 类非常有用,例如在测试数据库应用程序时。
希望这个答案能为您提供更多有关单元测试的信息,并帮助您从单元测试中获得更好的结果。
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.
我赞成拥有测试私有方法的能力。 当 xUnit 启动时,它的目的是在代码编写后测试功能。 测试接口足以达到此目的。
单元测试已发展为测试驱动开发。 能够测试所有方法对于该应用程序很有用。
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.
这个问题已经进入晚期,但我想我会分享我的做法。
基本上,我将所有单元测试类放在他们正在测试的程序集中的“UnitTest”命名空间中,该命名空间位于该程序集的“默认”下方 - 每个测试文件都包含在一个:
块中,所有这些都意味着a)它是未在发行版中分发,并且 b) 我可以使用
internal
/Friend
级别声明,而无需跳圈。与这个问题更相关的另一件事是使用
partial
类,它可用于创建测试私有方法的代理,例如测试诸如私有方法之类的东西返回一个整数值:在程序集的主类和测试类中:
显然,您需要确保在开发时不使用此方法,但如果您这样做,发布版本很快就会表明无意中调用了它。
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:
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:in the main classes of the assembly, and the test class:
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.
单元测试的主要目标是测试类的公共方法。 这些公共方法将使用那些私有方法。 单元测试将测试公开可用的行为。
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.
如果这不能回答问题,我们深表歉意,但使用反射、#if #endif 语句或使私有方法可见等解决方案并不能解决问题。 不使私有方法可见可能有多种原因......例如,如果它是生产代码并且团队正在回顾性地编写单元测试,该怎么办?
对于我正在从事的项目,只有 MSTest(遗憾的是)似乎有一种方法,使用访问器来对私有方法进行单元测试。
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.
您不测试私有函数。
有多种方法可以使用反射来访问私有方法和属性。 但这并不容易,我强烈反对这种做法。
你根本不应该测试任何不公开的东西。
如果您有一些内部方法和属性,您应该考虑将其更改为公共,或者将您的测试与应用程序一起发送(我并不真正认为这是一个问题)。
如果您的客户能够运行测试套件并看到您交付的代码实际上“工作”,我不认为这是一个问题(只要您不通过此泄露您的 IP)。 我在每个版本中都包含测试报告和代码覆盖率报告。
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.
从单元测试的理论来看,只需要测试合约。 即只有该类的公共成员。 但在实践中,开发人员通常也想测试内部成员 - 这也不错。 是的,它违背了理论,但在实践中有时它是有用的。
因此,如果您确实想测试内部成员,可以使用以下方法之一:
方法很简单
assembly
来自您正在测试的班级。
代码示例(伪代码):
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:
approach as simple
assembly
from your class under test.
Code example (pseudo code):
您可以将您的方法设置为内部保护,然后使用
程序集:InternalsVisibleTo("NAMESPACE")
到您的测试命名空间。
因此,不! 您无法访问私有方法,但这是一种解决方法。
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.
如果您需要访问类的非静态私有方法,可以尝试以下操作:
If you need to access a non-static private method of class, could try this:
我将使私有方法包可见。 这样你就可以保持它的私密性,同时仍然能够测试这些方法。 我不同意人们说公共接口是唯一应该测试的接口。 私有方法中通常存在非常关键的代码,仅通过外部接口无法正确测试这些代码。
所以这实际上可以归结为您是否更关心正确的代码或信息隐藏。 我想说包可见性是一个很好的折衷方案,因为为了访问这些方法,有人必须将他们的类放在您的包中。 这真的应该让他们三思而行,看看这是否真的是明智之举。
顺便说一句,我是一个 Java 人,所以包可见性在 C# 中可能被称为完全不同的东西。 可以说,两个类必须位于同一名称空间中才能访问这些方法。
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.