Java 单元测试调用多个私有方法的公共方法

Java 单元测试调用多个私有方法的公共方法,java,unit-testing,junit,Java,Unit Testing,Junit,我想测试一个调用多个私有方法的公共方法。我从之前提出的问题的所有答案中读到的内容各不相同。有人说,如果遇到这种情况,那么可能结构是错误的,或者调用其他没有任何逻辑的方法的方法不应该被测试,等等 我不清楚的是,我应该模拟这些私有方法(使用PowerMock或任何基于反射的库)并仅对该方法进行单元测试,还是应该提供不同类型的输入,以便测试所有案例,但也将调用私有方法。在后一种情况下,还是单元测试,因为我也会调用其他方法 ClassToTest类{ public void publicMethod(参

我想测试一个调用多个私有方法的公共方法。我从之前提出的问题的所有答案中读到的内容各不相同。有人说,如果遇到这种情况,那么可能结构是错误的,或者调用其他没有任何逻辑的方法的方法不应该被测试,等等

我不清楚的是,我应该模拟这些私有方法(使用PowerMock或任何基于反射的库)并仅对该方法进行单元测试,还是应该提供不同类型的输入,以便测试所有案例,但也将调用私有方法。在后一种情况下,还是单元测试,因为我也会调用其他方法

ClassToTest类{
public void publicMethod(参数){
试一试{
privateMethod1();
私有方法2(论点);
privateMethod3();
}捕获(例外情况除外){
privateMethod4();
}
}
}

首先,重要的是要理解,试图使单元测试套件完全独立于实现细节可能会导致效率低下的测试套件,也就是说,不适合查找所有可能发现的bug的测试套件。而且,发现bug是测试的一个主要目标(参见Myers、Badgett、Sandler:软件测试的艺术,或者Beizer:软件测试技术和许多其他内容)

同一接口的替代实现具有不同的潜在bug。fibonacci函数的迭代/递归实现的测试与使用Moivre/Binet的封闭形式表达式的实现或查找表实现的测试看起来不同

然而,单元测试还有一些次要目标。其中之一是避免在实现细节更改时测试不必要地中断。因此,测试不应该不必要地依赖于实现细节。始终首先尝试创建与实现无关的有用测试,然后添加特定于实现的测试。对于后者,测试内部(私有)方法(例如通过使其包可见)也可以是一个有效的选择-只要您知道缺点(如果内部方法被重命名、删除等,则需要维护测试代码),并权衡它们的优点

其次,很可能您不应该模仿私有方法,而应该将它们作为测试的一部分使用。我说很有可能,因为这取决于方法。嘲弄应该是有原因的(否则应该避免)。好的理由是:

  • 您不能轻易地使依赖组件(DOC)按照测试的预期行为
  • 调用DOC是否会导致任何非皮肤病行为(日期/时间、随机性、网络连接)
  • 测试设置过于复杂和/或维护密集(例如,需要外部文件)
  • 原始文档给测试代码带来了可移植性问题
  • 使用原始文档是否会导致生成/执行时间过长
  • 是否存在使测试不可靠的文档稳定性(成熟度)问题,或者更糟糕的是,文档还不可用

例如,您(通常)不会模拟标准库数学函数,如sin或cos,因为它们没有任何上述问题。您必须判断这是否也适用于您的私有方法。

密切相关:后者。甚至不要试图模仿私有方法。是的,它仍然是单元测试。有一个问题,大多数人说,在单元测试中,使用反射进行私有方法模拟/调用是一个糟糕的想法。如何通过反射设置私有字段值?还是“无法接受”吗?非常感谢你,德克,我明白了。第二个要点就是我需要的。我的私有方法是以确定性的方式运行的,基于只返回一个值的输入。但有一个问题,大多数人说,在单元测试中,使用反射进行私有方法模拟/调用是一个糟糕的想法。如何通过反射设置私有字段值?它仍然是“不可接受的”吗?正如我在回答中提到的,任何对实现细节的依赖都是以更脆弱的测试为代价的。好处可能超过这个代价,所以我一般不会说这是“不可接受的”。通过隐藏辅助方法背后的丑陋,通常可以降低风险。另一方面,helper方法也可能是通过公共API排除复杂设置的一个选项,从而保持更干净的一面。然而,对于情况A正确的东西对于情况B可能是错误的——这都是关于具体情况的权衡。