.net 你如何对私有方法进行单元测试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/250692/
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
How do you unit test private methods?
提问by Eric Labashosky
I'm building a class library that will have some public & private methods. I want to be able to unit test the private methods (mostly while developing, but also it could be useful for future refactoring).
我正在构建一个具有一些公共和私有方法的类库。我希望能够对私有方法进行单元测试(主要是在开发过程中进行,但也可能对未来的重构有用)。
What is the correct way to do this?
这样做的正确方法是什么?
采纳答案by TcKs
If you are using .net, you should use the InternalsVisibleToAttribute.
如果您使用 .net,则应使用InternalsVisibleToAttribute。
回答by Jeroen Heijmans
If you want to unit test a private method, something may be wrong. Unit tests are (generally speaking) meant to test the interface of a class, meaning its public (and protected) methods. You can of course "hack" a solution to this (even if just by making the methods public), but you may also want to consider:
如果您想对私有方法进行单元测试,可能会出现问题。单元测试(一般来说)旨在测试类的接口,即其公共(和受保护)方法。您当然可以“破解”一个解决方案(即使只是通过公开方法),但您可能还需要考虑:
- If the method you'd like to test is really worth testing, it may be worth to move it into its own class.
- Add more tests to the public methods that call the private method, testing the private method's functionality. (As the commentators indicated, you should only do this if these private methods's functionality is really a part in with the public interface. If they actually perform functions that are hidden from the user (i.e. the unit test), this is probably bad).
- 如果您要测试的方法确实值得测试,则可能值得将其移动到自己的类中。
- 向调用私有方法的公共方法添加更多测试,测试私有方法的功能。(正如评论者所指出的,只有当这些私有方法的功能确实是公共接口的一部分时才应该这样做。如果它们实际上执行对用户隐藏的功能(即单元测试),这可能很糟糕)。
回答by Seven
It might not be useful to test private methods. However, I also sometimes like to call private methods from test methods. Most of the time in order to prevent code duplication for test data generation...
测试私有方法可能没有用。但是,我有时也喜欢从测试方法调用私有方法。大多数时候为了防止测试数据生成的代码重复......
Microsoft provides two mechanisms for this:
微软为此提供了两种机制:
Accessors
配件
- Goto the class definition's source code
- Right-click on the name of the class
- Choose "Create Private Accessor"
- Choose the project in which the accessor should be created => You will end up with a new class with the name foo_accessor. This class will be dynamically generated during compilation and privides all members public available.
- 转到类定义的源代码
- 右键单击类名
- 选择“创建私人访问者”
- 选择应该在其中创建访问器的项目 => 您最终会得到一个名为 foo_accessor 的新类。此类将在编译期间动态生成,并将所有成员公开可用。
However, the mechanism is sometimes a bit intractable when it comes to changes of the interface of the original class. So, most of the times I avoid using this.
但是,当涉及到更改原始类的接口时,该机制有时会有点棘手。所以,大多数时候我避免使用它。
PrivateObject classThe other way is to use Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject
PrivateObject 类另一种方式是使用 Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject
// Wrap an already existing instance
PrivateObject accessor = new PrivateObject( objectInstanceToBeWrapped );
// Retrieve a private field
MyReturnType accessiblePrivateField = (MyReturnType) accessor.GetField( "privateFieldName" );
// Call a private method
accessor.Invoke( "PrivateMethodName", new Object[] {/* ... */} );
回答by Darrell Plank
I don't agree with the "you should only be interested in testing the external interface" philosophy. It's a bit like saying that a car repair shop should only have tests to see if the wheels turn. Yes, ultimately I'm interested in the external behavior but I like my own, private, internal tests to be a bit more specific and to the point. Yes, if I refactor, I may have to change some of the tests, but unless it's a massive refactor, I'll only have to change a few and the fact that the other (unchanged) internal tests still work is a great indicator that the refactoring has been successful.
我不同意“你应该只对测试外部接口感兴趣”的理念。这有点像说汽车维修店应该只测试车轮是否转动。是的,最终我对外部行为感兴趣,但我喜欢我自己的、私人的、内部测试更具体一点。是的,如果我重构,我可能需要更改一些测试,但除非是大规模重构,否则我只需要更改一些,并且其他(未更改的)内部测试仍然有效的事实是一个很好的指标重构成功。
You can try to cover all internal cases using only the public interface and theoretically it's possible to test every internal method (or at least every one that matters) entirely by using the public interface but you may have to end up standing on your head to achieve this and the connection between the test cases being run through the public interface and the internal portion of the solution they're designed to test may be difficult or impossible to discern. Having pointed, individual tests that guarantee that the internal machinery is working properly is well worth the minor test changes that come about with refactoring - at least that's been my experience. If you have to make huge changes to your tests for every refactoring, then maybe this doesn't make sense, but in that case, maybe you ought to rethink your design entirely. A good design should be flexible enough to allow for most changes without massive redesigns.
您可以尝试仅使用公共接口来覆盖所有内部情况,理论上可以完全使用公共接口来测试每个内部方法(或至少每个重要的方法),但您最终可能不得不站在自己的头上才能实现这与通过公共接口运行的测试用例与其设计用于测试的解决方案的内部部分之间的联系可能难以或无法辨别。指出,保证内部机制正常工作的个别测试非常值得重构带来的微小测试更改 - 至少这是我的经验。如果每次重构都必须对测试进行巨大更改,那么这可能没有意义,但在这种情况下,也许您应该完全重新考虑您的设计。
回答by Jason Hymanson
In the rare cases I have wanted to test private functions, I have usually modified them to be protected instead, and the I have written a subclass with a public wrapper function.
在极少数情况下我想测试私有函数,我通常将它们修改为受保护,并且我编写了一个带有公共包装函数的子类。
The Class:
班上:
...
protected void APrivateFunction()
{
...
}
...
Subclass for testing:
用于测试的子类:
...
[Test]
public void TestAPrivateFunction()
{
APrivateFunction();
//or whatever testing code you want here
}
...
回答by Big Kahuna
I think a more fundamental question should be asked is that why are you trying to test the private method in the first place. That is a code smell that you're trying to test the private method through that class' public interface whereas that method is private for a reason as it's an implementation detail. One should only be concerned with the behaviour of the public interface not on how it's implemented under the covers.
我认为应该问一个更基本的问题是,您为什么首先要尝试测试私有方法。这是一种代码味道,您试图通过该类的公共接口测试私有方法,而该方法是私有的,因为它是实现细节。人们应该只关心公共接口的行为,而不是它是如何在幕后实现的。
If I want to test the behaviour of the private method, by using common refactorings, I can extract its code into another class (maybe with package level visibility so ensure it's not part of a public API). I can then test its behaviour in isolation.
如果我想测试私有方法的行为,通过使用通用重构,我可以将其代码提取到另一个类中(可能具有包级可见性,因此确保它不是公共 API 的一部分)。然后我可以单独测试它的行为。
The product of the refactoring means that private method is now a separate class that has become a collaborator to the original class. Its behaviour will have become well understood via its own unit tests.
重构的产物意味着私有方法现在是一个单独的类,它已成为原始类的合作者。它的行为将通过它自己的单元测试得到很好的理解。
I can then mock its behaviour when I try to test the original class so that I can then concentrate on test the behaviour of that class' public interface rather than having to test a combinatorial explosion of the public interface and the behaviour of all its private methods.
然后,当我尝试测试原始类时,我可以模拟它的行为,这样我就可以专注于测试该类的公共接口的行为,而不必测试公共接口的组合爆炸及其所有私有方法的行为.
I see this analogous to driving a car. When I drive a car I don't drive with the bonnet up so I can see that the engine is working. I rely on the interface the car provides, namely the rev counter and the speedometer to know the engine is working. I rely on the fact that the car actually moves when I press the gas pedal. If I want to test the engine I can do checks on that in isolation. :D
我认为这类似于驾驶汽车。当我开车时,我不会把引擎盖打开,这样我就能看到发动机在工作。我依靠汽车提供的界面,即转速表和车速表来了解发动机是否在工作。我依赖于当我踩油门时汽车实际上会移动的事实。如果我想测试引擎,我可以单独进行检查。:D
Of course testing private methods directly may be a last resort if you have a legacy application but I would prefer that legacy code is refactored to enable better testing. Michael Feathers has written a great book on this very subject. http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
当然,如果您有遗留应用程序,直接测试私有方法可能是最后的手段,但我更希望对遗留代码进行重构以实现更好的测试。Michael Feathers 写了一本关于这个主题的好书。http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
回答by amazedsaint
Private types, internals and private members are so because of some reason, and often you don't want to mess with them directly. And if you do, chances are that you'll break later, because there is no guarantee that the guys who created those assemblies will keep the private/internal implementations as such.
私有类型、内部和私有成员由于某种原因而如此,通常您不想直接与它们混淆。如果你这样做了,你以后很可能会崩溃,因为不能保证创建这些程序集的人会保持私有/内部实现。
But ,at times, when doing some hacks/exploration of compiled or third party assemblies, I have myself ended up wanting to initialize a private class or a class with a private or internal constructor. Or, at times, when dealing with pre-compiled legacy libraries that I can't change - I end up writing some tests against a private method.
但是,有时,在对编译或第三方程序集进行一些黑客/探索时,我自己最终想要初始化一个私有类或一个具有私有或内部构造函数的类。或者,有时,在处理我无法更改的预编译遗留库时 - 我最终会针对私有方法编写一些测试。
Thus born the AccessPrivateWrapper - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html- it's is a quick wrapper class that'll make the job easy using C# 4.0 dynamic features and reflection.
因此诞生了 AccessPrivateWrapper - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html- 它是一个快速包装类,可以使用 C# 4.0 动态特性和反射使工作变得容易。
You can create internal/private types like
您可以创建内部/私有类型,例如
//Note that the wrapper is dynamic
dynamic wrapper = AccessPrivateWrapper.FromType
(typeof(SomeKnownClass).Assembly,"ClassWithPrivateConstructor");
//Access the private members
wrapper.PrivateMethodInPrivateClass();
回答by Unknown
Well you can unit test private method in two ways
那么您可以通过两种方式对私有方法进行单元测试
you can create instance of
PrivateObjectclass the syntax is as followsPrivateObject obj= new PrivateObject(PrivateClass); //now with this obj you can call the private method of PrivateCalss. obj.PrivateMethod("Parameters");You can use reflection.
PrivateClass obj = new PrivateClass(); // Class containing private obj Type t = typeof(PrivateClass); var x = t.InvokeMember("PrivateFunc", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { 5 });
您可以创建
PrivateObject类的实例,语法如下PrivateObject obj= new PrivateObject(PrivateClass); //now with this obj you can call the private method of PrivateCalss. obj.PrivateMethod("Parameters");您可以使用反射。
PrivateClass obj = new PrivateClass(); // Class containing private obj Type t = typeof(PrivateClass); var x = t.InvokeMember("PrivateFunc", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { 5 });
回答by philsquared
I've also used the InternalsVisibleToAttribute method. It's worth mentioning too that, if you feel uncomfortable making your previously private methods internal in order to achieve this, then maybe they should not be the subject of direct unit tests anyway.
我还使用了 InternalsVisibleToAttribute 方法。还值得一提的是,如果为了实现这一点而将以前的私有方法置于内部感到不舒服,那么也许它们无论如何都不应该成为直接单元测试的主题。
After all, you're testing the behaviourof your class, rather than it's specific implementation- you can change the latter without changing the former and your tests should still pass.
毕竟,您正在测试您的类的行为,而不是它的具体实现- 您可以更改后者而不更改前者,并且您的测试仍然应该通过。
回答by Venkat
There are 2 types of private methods. Static Private Methods and Non Static Private methods(Instance Methods). The following 2 articles explain how to unit test private methods with examples.
有两种类型的私有方法。静态私有方法和非静态私有方法(实例方法)。以下 2 篇文章解释了如何通过示例对私有方法进行单元测试。

