如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
如何使用JUnit测试具有内部私有方法、字段或嵌套类的类?
仅仅为了能够运行测试而更改方法的访问修饰符似乎是不好的。
当前回答
下面是我测试私有字段的通用函数:
protected <F> F getPrivateField(String fieldName, Object obj)
throws NoSuchFieldException, IllegalAccessException {
Field field =
obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (F)field.get(obj);
}
其他回答
请参见下面的示例;
应添加以下导入语句:
import org.powermock.reflect.Whitebox;
现在,您可以直接传递具有私有方法、要调用的方法名和其他参数的对象,如下所示。
Whitebox.invokeMethod(obj, "privateMethod", "param1");
正如其他人所说。。。不要直接测试私有方法。以下是一些想法:
保持所有方法的规模和重点(易于测试,易于发现错误)使用代码覆盖工具。我喜欢Cobertura(哦,快乐的一天,它看起来像是一个新版本!)
在单元测试上运行代码覆盖率。如果您发现方法没有经过充分测试,请添加到测试中以提高覆盖率。目标是100%的代码覆盖率,但要意识到你可能无法做到这一点。
在使用ExpectedException时,对Cem Catikka的答案进行了快速补充:
请记住,预期的异常将被包装在InvocationTargetException中,因此为了获得异常,必须抛出收到的InvocationTargetException的原因。类似于(在BizService上测试私有方法validateRequest()):
@Rule
public ExpectedException thrown = ExpectedException.none();
@Autowired(required = true)
private BizService svc;
@Test
public void testValidateRequest() throws Exception {
thrown.expect(BizException.class);
thrown.expectMessage(expectMessage);
BizRequest request = /* Mock it, read from source - file, etc. */;
validateRequest(request);
}
private void validateRequest(BizRequest request) throws Exception {
Method method = svc.getClass().getDeclaredMethod("validateRequest", BizRequest.class);
method.setAccessible(true);
try {
method.invoke(svc, request);
}
catch (InvocationTargetException e) {
throw ((BizException)e.getCause());
}
}
我最近遇到了这个问题,并编写了一个名为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));
如果您想测试不能更改代码的遗留应用程序的私有方法,Java的一个选项是jMockit,它将允许您创建对象的模拟,即使它们对类是私有的。