我需要对一个方法进行单元测试,并且我想模拟该行为,以便可以测试该方法中代码的必要部分。
为此,我想访问我正在尝试测试的方法内的私有(private)方法返回的对象。我创建了一个示例代码来给出我想要实现的目标的基本概念。
主类
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");
}
最佳答案
访问私有(private)只有两种方法:
- 使用反射
- 扩大范围
- 也许等待 Java 9 使用新的作用域机制?
我会将范围修饰符从私有(private)范围更改为包范围。使用反射进行重构并不稳定。如果您使用像 PowerMock 这样的助手也没关系。它们仅减少反射周围的样板代码。
但最重要的一点是你不应该在白盒测试中测试得太深。这可能会使测试装置爆炸。尝试将代码分割成更小的部分。
方法“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");
}
关于java - 在公共(public)方法中拦截私有(private)方法返回的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42343667/