如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
如果你担心没有像很多帖子所建议的那样测试私有方法,那么考虑一下代码覆盖工具将准确地确定你的代码被测试了多少以及泄漏的地方,所以这样做是可以接受的。
将问题作者引向“变通方法”的答案对社区造成了巨大的伤害。测试是所有工程学科的主要组成部分。你不会想买一辆没有经过适当测试的汽车,而且测试的方式很有意义,那么为什么有人会想购买或使用测试不好的软件呢?人们这样做的原因可能是因为测试不好的软件的影响是事后才感受到的,我们通常不会把它们与身体伤害联系起来。
这是一种非常危险的观念,很难改变,但我们有责任提供安全的产品,而不管管理层如何欺负我们。想想Equifax黑客。。。
我们必须努力营造一个鼓励良好软件工程实践的环境。这并不意味着排斥我们中那些不认真对待自己手艺的弱者/懒惰者,而是创造一种责任感和自我反思的现状,鼓励每个人在精神和技能上追求成长。
我仍在学习,可能自己也有错误的看法/观点,但我坚信,我们需要对良好做法负责,避免不负责任的黑客或解决问题的方法。
其他回答
私有方法只能在同一类中访问。因此,无法从任何测试类测试目标类的“私有”方法。一种方法是,您可以手动执行单元测试,也可以将方法从“私有”更改为“受保护”。
然后,受保护的方法只能在定义类的同一个包中访问。因此,测试目标类的受保护方法意味着我们需要在与目标类相同的包中定义测试类。
如果以上所有内容都不符合您的要求,请使用反射方式访问私有方法。
今天,我推出了一个Java库来帮助测试私有方法和字段。它的设计考虑到了Android,但它确实可以用于任何Java项目。
如果您有一些带有私有方法、字段或构造函数的代码,可以使用BoundBox。它正是你想要的。下面是一个测试示例,它访问Android活动的两个私有字段来测试它:
@UiThreadTest
public void testCompute() {
// Given
boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());
// When
boundBoxOfMainActivity.boundBox_getButtonMain().performClick();
// Then
assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}
BoundBox使测试私有/受保护的字段、方法和构造函数变得容易。你甚至可以访问被继承隐藏的东西。实际上,BoundBox打破了封装。它会让您通过反射访问所有这些内容,但在编译时会检查所有内容。
它非常适合测试一些遗留代码。小心使用。;)
正如其他人所说。。。不要直接测试私有方法。以下是一些想法:
保持所有方法的规模和重点(易于测试,易于发现错误)使用代码覆盖工具。我喜欢Cobertura(哦,快乐的一天,它看起来像是一个新版本!)
在单元测试上运行代码覆盖率。如果您发现方法没有经过充分测试,请添加到测试中以提高覆盖率。目标是100%的代码覆盖率,但要意识到你可能无法做到这一点。
如果您的测试类与应该测试的类在同一个包中呢?
当然,在另一个目录中,源代码使用src&classes,测试类使用test/src和test/classes。让类和测试/类位于类路径中。
我想分享一条关于测试的规则,这条规则尤其与本主题相关:
我认为你不应该为了更轻松地编写测试。
在其他帖子中有一些建议,说你应该调整原始类以测试私有方法-请先将此警告标记为红色。
如果我们将方法/字段的可访问性更改为包私有或受保护,只是为了让测试可以访问它,那么我们就违背了私有访问指令存在的目的。
当我们想要进行测试驱动的开发时,为什么要有私有字段/方法/类?那么,我们是否应该将所有内容都声明为私有的,甚至是公共的,这样我们就可以不费力地进行测试了-我不这么认为。
从另一个角度来看:测试不应影响生产应用程序的性能和执行。
如果我们仅仅为了更容易的测试而更改生产代码,这可能会在某种程度上影响性能和应用程序的执行。
如果有人开始将私有访问更改为包私有,那么开发人员最终可能会想出其他“巧妙的想法”,向原始类添加更多代码。这会给可读性带来额外的噪音,并会影响应用程序的性能。
随着私有访问更改为限制性较小的访问,我们为开发人员在应用程序的未来开发中滥用新情况提供了可能性。我们不是强迫他/她以正确的方式发展,而是用新的可能性引诱他/她,让他/她有能力在未来做出错误的选择。
当然,这条规则可能会有一些例外,但如果理解清楚,规则是什么,例外是什么?我们需要绝对确定我们知道为什么会引入这种例外。