我需要单元测试一种方法,我想模拟该行为,以便可以在方法中测试代码的必要部分。
为此,我想访问我要测试的方法内部通过私有方法返回的对象。我创建了一个示例代码,以对我要实现的目标提供一个基本的想法。
main.class
Class Main {
public String getUserName(String userId) {
User user = null;
user = getUser(userId);
if(user.getName().equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
private User getUser(String userId) {
// find the user details in database
String name = ""; // Get from db
String address = ""; // Get from db
return new User(name, address);
}
}
测试类
@Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = new Main();
// I need to access the user object returned by getUser(userId)
// and spy it, so that when user.getName() is called it returns Stack
main.getUserName("124");
}
只有两种方法可以访问私人:
- 使用反射
- 扩展范围
- 也许等待Java 9使用新的示波器机制?
我会将范围修改器从私有变为包装范围更改。使用反射不稳定用于重构。使用PowerMock之类的帮助者都没关系。他们只会在反射周围减少锅炉板代码。
,但最重要的一点是您不应在Whitbox测试中测试太深。这可以使测试设置爆炸。尝试将代码切成小块。
唯一的信息" getUsername"来自用户对象的需求是名称。它将验证名称并提出异常或退还。因此,不必在测试中引入用户对象。
所以我的建议是,您应该将用户对象从用户对象重新提取的代码中提取到单独的方法中,并制作此方法包范围。现在,无需仅模拟用户对象。但是该方法的最小信息可以正常工作。
class Main {
public String getUserName(String userId) {
String username = getUserNameFromInternal(userId);
if (userName.equals("Stack")) {
throw new CustomException("StackOverflow");
}
return user.getName();
}
String getUserNameFromInternal(String userId) {
User user = getUser(userId);
return user.getName();
}
...
}
测试:
@Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
Main main = Mockito.mock(new Main());
Mockito.when(main.getUserNameInternal("124")).thenReturn("Stack");
main.getUserName("124");
}
您的私人方法中呼叫new
的问题。
答案不是转向PowerMock;或更改该方法的可见性。
合理的答案是"提取"对"给我用户对象的东西"中的依赖性的"提取";并将该类的实例提供给您的"主要"类。因为那样,您就可以简单地模拟该"工厂"对象;并让它做任何您想做的事。
含义:您当前的代码只是难以测试。您没有解决由于这引起的问题的工作,而是花时间学习如何编写易于测试的代码;例如,通过观看这些视频作为起点。
鉴于您的最新评论:当您处理旧版代码时,您真的在寻求使用PowerMockito。要理解的关键部分:您不"模拟"该私人方法;您宁愿嘲笑对new User()
的调用;如下所示。
您可以使用PowerMock的模拟狂,但我不建议这样做。如果您有这样的问题,通常意味着您的设计不好。为什么不保护该方法?