如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
JUnit.org常见问题解答页面的答案:
但如果你必须。。。如果您使用的是JDK1.3或更高版本,则可以使用反射来颠覆访问控制机制。有关如何使用它的详细信息,请阅读本文。如果您使用的是JDK1.6或更高版本,并且使用@测试时,可以使用Dp4j在测试方法中注入反射。对于有关如何使用它的详细信息,请参阅此测试脚本。
P.S.我是Dp4j的主要贡献者。问我你是否需要帮助。:)
其他回答
私有方法被公共方法使用。否则,它们就是死代码。这就是为什么要测试公共方法,断言公共方法的预期结果,从而断言它使用的私有方法。
在公共方法上运行单元测试之前,应该通过调试来测试私有方法。
也可以使用测试驱动开发来调试它们,调试单元测试,直到满足所有断言。
我个人认为最好使用TDD创建类;创建公共方法存根,然后使用预先定义的所有断言生成单元测试,这样在编写代码之前就可以确定方法的预期结果。这样,就不会走上使单元测试断言符合结果的错误道路。然后,当所有单元测试通过时,您的类是健壮的并满足要求。
在过去,我曾为Java使用过反射,在我看来这是一个很大的错误。
严格来说,您不应该编写直接测试私有方法的单元测试。您应该测试的是类与其他对象的公共契约;您不应该直接测试对象的内部。如果另一个开发人员想要对类进行一个小的内部更改,这不会影响类的公共契约,那么他/她就必须修改基于反射的测试,以确保它正常工作。如果在整个项目中重复这样做,那么单元测试就不再是代码健康状况的有用度量,而开始成为开发的障碍,成为开发团队的烦恼。
相反,我建议使用一个代码覆盖工具,例如Cobertura,以确保您编写的单元测试在私有方法中提供代码的适当覆盖。通过这种方式,您可以间接测试私有方法正在做什么,并保持更高级别的灵活性。
我最近遇到了这个问题,并编写了一个名为Picklock的小工具,它避免了显式使用Java反射API的问题,两个示例:
通过Java反射调用方法,例如private void方法(String s)
Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");
通过Picklock调用方法,例如private void方法(String s)
interface Accessible {
void method(String s);
}
...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");
设置字段,例如私有BigInteger金额;-通过Java反射
Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));
设置字段,例如私有BigInteger金额;-由Picklock提供
interface Accessible {
void setAmount(BigInteger amount);
}
...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));
测试私有方法的最佳方法是通过另一个公共方法。如果无法做到这一点,则以下条件之一为真:
私有方法是死代码您正在测试的类附近有设计气味您尝试测试的方法不应是私有的
JUnit.org常见问题解答页面的答案:
但如果你必须。。。如果您使用的是JDK1.3或更高版本,则可以使用反射来颠覆访问控制机制。有关如何使用它的详细信息,请阅读本文。如果您使用的是JDK1.6或更高版本,并且使用@测试时,可以使用Dp4j在测试方法中注入反射。对于有关如何使用它的详细信息,请参阅此测试脚本。
P.S.我是Dp4j的主要贡献者。问我你是否需要帮助。:)