我正在尝试编写一个实用程序方法,以便在被测试的类中轻松调用私有方法。 我有这个:
private Object callPrivateMethod(String methodName, Object subject, Object... parameters) {
try {
Class<?>[] paramTypes = new Class<?>[parameters.length];
for (int index=0; index<parameters.length; index++) {
paramTypes[index] = parameters[index].getClass();
}
Method method = subject.getClass().getDeclaredMethod(methodName, paramTypes);
method.setAccessible(true);
return method.invoke(subject, parameters);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
return null;
}
}
但是当我尝试使用此代码调用它时:
List<Session> sessions = new ArrayList<Session>();
// fill the array list
String sessionLines = (String) callPrivateMethod("getSessionsForEmail", emailSender, sessions);
我得到了这个例外:
java.lang.NoSuchMethodException: staffing.server.email.EmailSender.getSessionsForEmail(java.util.ArrayList)
EmailSender(测试中的类)中的方法签名如下所示:
private String getSessionsForEmail(List<Session> sessions) {
//do stuff
}
试图弄清楚为什么反射找不到方法。与List和ArrayList不完全相同的类是什么?如果是这样,我该怎么办?
答案 0 :(得分:6)
最佳做法是不直接测试私有方法。通过公共和/或受保护的方法访问它们,我们正在测试系统在生产中的表现。此方法还允许您通过公共/受保护方法发送所有数据组合来管理测试覆盖率。
可以通过在测试源文件夹中使用相同的包名来测试受保护的方法。
如果必须测试私有方法,那么您可以使用Powermock等模拟工具,而不是自己进行反射,最好使用Mockito。这两个工具都与JUnit有很好的集成。这是一个陡峭的学习曲线,但值得投资。以下是更多详细信息:Testing Private method using mockito
答案 1 :(得分:4)
您的代码尝试查找以ArrayList
(具体类sessions
)为参数的方法。但是您的方法不会将ArrayList
作为参数。它需要List
作为参数。
除了参数值之外,您还需要传递方法参数的类型。
或者您可以重构代码并使方法受保护或受包保护,或者将其作为公共方法放在另一个协作类中。
答案 2 :(得分:0)
目前的推理说你不应该测试私有方法。它们是特定于实现的,应该通过调用它们的方法进行测试。或者他们应该被提取到他们自己的班级并通过它进行测试。我们的想法是,如果你有私人方法做得太多,他们需要单独测试,你的课程做得太多,应该分手。
以这种方式看待它有很多好处,而不是至少逃避不得不攻击你的班级来测试它。
答案 3 :(得分:0)
如果您真的希望通过自己的实现取得成功,我觉得查看可能有用:Type erasure in Java。
否则,正如Akber Choudhry指出的那样,Mockito附带了一个很好的实用程序包,名为org.powermock.reflect.Whitebox。我肯定会用它。
最后,我不会说永远不会测试私有方法,但如果你打算测试它们,请三思而后行。保持基于反射的方法并不是最简单的方法,而且非常容易出错。
答案 4 :(得分:0)
这可以通过 JUnit4 + Mockito 完成。
要模拟私有方法,我们可以简单地使用mockit.Deencapsulation包:
Deencapsulation.invoke(myService, "methodName", arg1, arg2);
我们可以根据要求用Mockito.anyString()等替换参数。