如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
在尝试了Cem Catikkas使用Java反射的解决方案后,我不得不说,他的解决方案比我在这里描述的更优雅。然而,如果您正在寻找使用反射的替代方案,并且能够访问您正在测试的源代码,那么这仍然是一个选项。
测试类的私有方法可能有好处,特别是在测试驱动开发中,您希望在编写任何代码之前设计小型测试。
创建一个可以访问私有成员和方法的测试,可以测试那些只访问公共方法而难以专门针对的代码区域。如果公共方法涉及多个步骤,它可以由多个私有方法组成,然后可以单独测试。
优势:
可以测试到更精细的粒度
缺点:
测试代码必须位于文件作为源代码更难维护与.class输出文件类似,它们必须保持在源代码中声明的相同包中
然而,如果连续测试需要这种方法,这可能是一个信号,表明应该提取私有方法,可以以传统的公共方式进行测试。
下面是一个复杂的例子,说明这是如何工作的:
// Import statements and package declarations
public class ClassToTest
{
private int decrement(int toDecrement) {
toDecrement--;
return toDecrement;
}
// Constructor and the rest of the class
public static class StaticInnerTest extends TestCase
{
public StaticInnerTest(){
super();
}
public void testDecrement(){
int number = 10;
ClassToTest toTest= new ClassToTest();
int decremented = toTest.decrement(number);
assertEquals(9, decremented);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(StaticInnerTest.class);
}
}
}
内部类将编译为ClassToTest$StaticInnerTest。
另请参阅:Java提示106:静态内部类以获取乐趣和利润
其他回答
如果您有一些遗留的Java应用程序,并且不允许更改方法的可见性,那么测试私有方法的最佳方法是使用反射。
在内部,我们使用助手来获取/设置私有和私有静态变量,以及调用私有和私有的静态方法。以下模式将允许您执行与私有方法和字段相关的任何操作。当然,您不能通过反射来更改私有静态final变量。
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
对于字段:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
笔记:TargetClass.getDeclaredMethod(methodName,argClasses)允许您查看私有方法。同样的事情也适用于getDeclaredField。需要setAccessible(true)才能与private一起玩。
从本文:使用JUnit和SuiteRunner测试私有方法(Bill Venners)中,您基本上有4个选项:
不要测试私有方法。授予方法包访问权限。使用嵌套测试类。使用反射。
您可以关闭反射的Java访问限制,这样私有就没有什么意义了。
setAccessible(true)调用实现了这一点。
唯一的限制是ClassLoader可能不允许您这样做。
有关在Java中实现这一点的方法,请参阅颠覆单元测试的Java访问保护(Ross Burton)。
私有方法由公共方法调用,因此公共方法的输入也应测试这些公共方法调用的私有方法。当公共方法失败时,这可能是私有方法的失败。
首先,我要抛出一个问题:为什么你的私人成员需要隔离测试?它们是否如此复杂,提供了如此复杂的行为,以至于需要在公共表面之外进行测试?这是单元测试,而不是“代码行”测试。别为小事操心。
如果它们是那么大,足够大,以至于这些私有成员都是一个复杂度很大的“单元”,那么考虑将这些私有成员从这个类中重构出来。
如果重构不合适或不可行,在进行单元测试时,是否可以使用策略模式来替换对这些私有成员函数/成员类的访问?在单元测试中,该策略将提供额外的验证,但在发布版本中,它将是简单的传递。