如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
您可以关闭反射的Java访问限制,这样私有就没有什么意义了。
setAccessible(true)调用实现了这一点。
唯一的限制是ClassLoader可能不允许您这样做。
有关在Java中实现这一点的方法,请参阅颠覆单元测试的Java访问保护(Ross Burton)。
其他回答
今天,我推出了一个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打破了封装。它会让您通过反射访问所有这些内容,但在编译时会检查所有内容。
它非常适合测试一些遗留代码。小心使用。;)
我倾向于不测试私人方法。这里有疯狂。我个人认为,你应该只测试你公开的接口(包括受保护的和内部的方法)。
请参见下面的示例;
应添加以下导入语句:
import org.powermock.reflect.Whitebox;
现在,您可以直接传递具有私有方法、要调用的方法名和其他参数的对象,如下所示。
Whitebox.invokeMethod(obj, "privateMethod", "param1");
我最近遇到了这个问题,并编写了一个名为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));
PowerMockito就是为此而生的。
使用Maven依赖项:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.7</version>
<scope>test</scope>
</dependency>
那你就可以了
import org.powermock.reflect.Whitebox;
...
MyClass sut = new MyClass();
SomeType rval = Whitebox.invokeMethod(sut, "myPrivateMethod", params, moreParams);