如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?

仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。


当前回答

从测试框架测试Java私有方法的最佳合法方法是在方法上添加@VisibleForTesting注释,因此相同的方法将像公共方法一样在测试框架中可见。

其他回答

对于Java,我会使用反射,因为我不喜欢仅仅为了测试而更改对声明方法的包的访问。然而,我通常只测试公共方法,这也应该确保私有方法正常工作。

不能使用反射从所有者类外部获取私有方法,私有修饰符也会影响反射

这不是真的。你当然可以,正如塞姆·卡提卡斯的回答中所提到的。

如果使用Spring,请使用此实用程序类:

ReflectionTestUtils.invokeMethod(new ClassName(), "privateMethodName");

私有方法由公共方法调用,因此公共方法的输入也应测试这些公共方法调用的私有方法。当公共方法失败时,这可能是私有方法的失败。

您可以关闭反射的Java访问限制,这样私有就没有什么意义了。

setAccessible(true)调用实现了这一点。

唯一的限制是ClassLoader可能不允许您这样做。

有关在Java中实现这一点的方法,请参阅颠覆单元测试的Java访问保护(Ross Burton)。

您可以使用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