我正在尝试根据行为驱动开发进行编程, 这表明在没有写入的情况下不应写入任何代码行 第一次失败的单元测试。
我的问题是,如何使用私有方法使用BDD?
我如何对私有方法进行单元测试?
有没有比以下更好的解决方案:
- 首先公开私人方法,然后将其私有化
当我编写使用这些私有方法的公共方法时;
或
- 在C#中使所有私有方法都在内部并使用InternalsVisibleTo
属性。
答案 0 :(得分:20)
当您首先编写代码测试时,您将针对公共接口进行编写。目前没有私人方法。
然后编写代码以通过测试。如果将任何代码考虑到私有方法中,那么这并不重要 - 它应该仍然存在,只是因为公共接口使用它。
如果代码没有先写入测试,那么 - 在.net中,无论如何 - 反射可以用来直接激活私有方法;虽然这是一种不得已的技术。
答案 1 :(得分:11)
私有方法是内部实现细节。它们不应该直接测试,因为它们将通过测试您的公共接口间接测试。如果由于某种原因在完全测试公共接口时未涵盖私有方法,则不需要私有方法,并且应该将其删除。
通常,将测试代码绑定到私有实现细节是个坏主意。这会将您的测试与那些私密细节相结合,从而降低您随意更改这些细节的自由,即使它们不会影响面向公众的界面和行为。这增加了编写和维护单元测试所需的工作量,这是一个负面的事情。你应该争取尽可能多的覆盖,同时只绑定到公共接口。
答案 2 :(得分:9)
简答:您不测试私人方法。
如果编程良好,测试的代码覆盖率应隐式测试私有方法。
答案 3 :(得分:7)
如果存在私有方法,则由公共方法使用。因此,我会为公共方法编写测试。
我编写测试来测试类的公共部分。如果该类设计得很好,那么默认情况下会对私有部件进行测试。
如果没有从公共方法调用私有方法,那么它为什么存在?
在你的情况下,我会做以下
* Write failing test for the public method
* Write public method that calls the private method that doesn't exist yet(test still fails as your class is incomplete
* Write the private method
* Test should now pass
答案 4 :(得分:7)
简短回答:您无法测试私有方法。
答案很长:您无法测试私有方法,但如果您倾向于测试其中的任何内容,请考虑重构您的代码。有两种简单的方法:
第一个很简单,但是当你编写更多测试时,你会倾向于让自己的脚射击,而后者则会促进更好的代码和测试设计。
答案:好的,所以我骗了。您可以借助一些反射魔法来测试私有方法(某些TDD工具支持测试私有方法)。根据我的经验,它会导致复杂的单元测试。卷积单元测试会导致代码更糟糕。更糟糕的代码导致愤怒。愤怒导致仇恨。仇恨导致痛苦 ......
生产代码变得更糟的直接影响是,被测试的课程往往变得庞大并处理许多事情(违反单一责任原则)并且难以维护。这违背了TDD的目的,即使生产代码可测试,可扩展,更重要的是:可重用。
如果您正在为部署的类编写测试,则可以调查调用私有方法的所有内容并相应地编写测试。如果你有机会重写课程,那么请通过拆分课程来重构它。如果你很幸运,那么你最终会得到一些可以利用的代码重用。
答案 5 :(得分:2)
您应该只测试类的外部API,即公共方法。如果您的测试没有在私有方法中访问代码,那么您需要编写更多测试或重构该类。
测试API的全部意义,特别是将分发给第三方的API,只要你不打破外部合同,就可以根据需要更改类的内部结构。这是公共方法。
正如您所知,这是BDD使用模拟类在“传统”TDD中发挥作用的地方,其中每个方法调用都必须提前设置以进行测试。我不是其中任何一方的专家,希望其他人可以比我更好地回答那个问题。
答案 6 :(得分:2)
我同意关于不测试私有方法本身以及测试应该针对公共API编写的观点,但是还有另一个选项,你没有在上面列出。
你可以使方法受到保护,然后从被测试的类派生。您可以在派生类上使用公共方法公开基本受保护方法,例如
public class TestableClassToTest : ClassToTest
{
public new void MethodToTest()
{
base.MethodToTest();
}
}
您可能已经使用此提取和覆盖模式来覆盖依赖注入的基类的虚拟属性,在这种情况下,这可能是您可行的选择。
答案 7 :(得分:2)
Mbunit Reflector为您提供帮助。
Reflector objectReflection = new Reflector(new ObjectWithprivateMethods());
objectReflection.InvokeMethod(AccessModifier.NonPublic,,"Add",1,6));
答案 8 :(得分:2)
我们可以分别使用PrivateType和PrivateObject对静态和实例私有方法进行单元测试。以下2篇文章解释了这些技术
答案 9 :(得分:1)
如果你发现自己想要测试一个私有方法,那么它有一些复杂的东西你可能想要测试它,这是一种设计气味。将该方法暴露在界面上只会将一种气味换成另一种气味。
重构时间:)
通常我将内部复杂性分解为辅助类。但是,请检查“功能羡慕”或“不恰当的亲密关系”的方法。生活方法可能有更好的地方。现在使用.net中的扩展方法,即使是基类型也可能是一个很好的候选者。
祝你好运
答案 10 :(得分:1)
如果你真的相信私有方法足够复杂,它应该得到它自己的单元测试 - 它表明你的类做得太多了,你应该将部分或全部私有方法提取到自己的类中在界面后面。
在测试原始类时模拟界面。您现在应该拥有一个新类的公共访问器,这是以前的私有方法。
有时在处理编写不好或未使用TDD编写的旧代码时,可能需要测试私有类。在这种情况下,您应该使用反射,但在可能的情况下更新代码以更接近TDD方法。
答案 11 :(得分:1)
我已经与它抗争了一个多月,但找到了答案:
var objectOfPrivateMethod = new ObjectOfPrivateMethod(); //yes here is contructor
object[] arguments = { }; // here as Object you provide arguments
var extractedPrivateMethod = typeof(ObjectOfPrivateMethod).GetMethod("Name_Of_Private_Method", BindingFlags.NonPublic|BindingFlags.Static); //if fails returns null. delete flag static if it's not static. Returns your method as an object.
Assert.AreNotEqual(null, extractedPrivateMethod, "Mathod does not exist"); // good to catch if even exists.
object result = extractedPrivateMethod.Invoke(null, arguments); // here as object you'll get return value of your function. change null for object of class where is method, if your method is not static
仅此而已。