如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
您可以使用PowerMockito为要测试的私有方法中调用/使用的私有字段和私有方法设置返回值:
例如,为私有方法设置返回值:
MyClient classUnderTest = PowerMockito.spy(new MyClient());
// Set the expected return value
PowerMockito.doReturn(20).when(classUnderTest, "myPrivateMethod", anyString(), anyInt());
// This is very important. Otherwise, it will not work
classUnderTest.myPrivateMethod();
// Setting the private field value as someValue:
Whitebox.setInternalState(classUnderTest, "privateField", someValue);
最后,您可以通过以下方式验证您的私有方法:
String msg = Whitebox.invokeMethod(obj, "privateMethodToBeTested", "param1");
Assert.assertEquals(privateMsg, msg);
Or
如果classUnderTest私有方法不返回值,但它设置了另一个私有字段,则可以获取该私有字段值以查看其设置是否正确:
// To get the value of a private field
MyClass obj = Whitebox.getInternalState(classUnderTest, "foo");
assertThat(obj, is(notNull(MyClass.class))); // Or test value
其他回答
私有方法由公共方法调用,因此公共方法的输入也应测试这些公共方法调用的私有方法。当公共方法失败时,这可能是私有方法的失败。
要用大型而古怪的类测试遗留代码,能够测试我现在正在编写的一个私有(或公共)方法通常非常有用。
我在Java中使用junitx.util.PrivateAccessor包。它有很多用于访问私有方法和私有字段的有用的一行程序。
import junitx.util.PrivateAccessor;
PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);
首先,我要抛出一个问题:为什么你的私人成员需要隔离测试?它们是否如此复杂,提供了如此复杂的行为,以至于需要在公共表面之外进行测试?这是单元测试,而不是“代码行”测试。别为小事操心。
如果它们是那么大,足够大,以至于这些私有成员都是一个复杂度很大的“单元”,那么考虑将这些私有成员从这个类中重构出来。
如果重构不合适或不可行,在进行单元测试时,是否可以使用策略模式来替换对这些私有成员函数/成员类的访问?在单元测试中,该策略将提供额外的验证,但在发布版本中,它将是简单的传递。
您可以关闭反射的Java访问限制,这样私有就没有什么意义了。
setAccessible(true)调用实现了这一点。
唯一的限制是ClassLoader可能不允许您这样做。
有关在Java中实现这一点的方法,请参阅颠覆单元测试的Java访问保护(Ross Burton)。
对于Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法的包的访问。然而,我通常只测试公共方法,这也应该确保私有方法正常工作。
不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射
这不是真的。你当然可以,正如塞姆·卡提卡斯的回答中所提到的。