据我了解,Mockito.verify() 用于确保使用所需参数调用模拟方法。但我不明白这样做的意图。我经常看到类似这样的测试:
public class UserDAO {
public long create(User user) {
//...
}
}
public class UserService {
private UserDAO userDAO;
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
public long createUser(User user) {
return userDAO.create(user);
}
}
public class UserServiceTest {
@Test
public void testCreateUser() {
UserDAO userDAO = mock(UserDAO.class);
when(userDAO.create(any(User.class))).thenReturn(anyLong());
UserService = new UserService(userDAO);
User user = new User("John Smith");
userService.createUser(user);
verify(userDAO).create(user);
}
}
测试验证当调用UserService 的createUser 方法时,是否调用UserDAO 的create 方法。看起来很荒谬。如果我更改 UserService 的实现,使其不调用 UserDAO 的方法,即使实现正确,我的测试也会失败。
我承认,在某些情况下,可能需要验证该方法被调用的确切次数,但这种情况并不常见。
很可能我不理解验证的概念,并且它不是特定于mockito的功能。您能用简单的语言解释一下它什么时候真正有意义吗?
最佳答案
verify()
方法是一种白盒测试的工具。但这不是您想要测试的实际实现,而是测试某种消息(方法调用)是否发送到底层,或者 - 更准确地说 - 指定由于执行测试代码而使用 API。
测试通常包含以下步骤:
- 准备输入(输入参数、环境、(模拟)系统等),
- 调用代码进行测试
- 将实际结果(输出参数、环境变化)与预期结果(一组假设)进行比较
但是预期的结果不一定是一些输出数据,而是对环境的一些改变。但是,如果您已经模拟了需要定义的环境,那么您的代码如何影响环境,并且通常通过 API 完成对环境(或其他组件)的访问。
让我们以create
为例方法为例。该方法没有返回值,但假设已在底层数据层(环境)上创建了数据集。当你模拟了数据层后,在没有存储的情况下,你将如何验证某些数据是否已存储?因此,假设除了调用 create
之外没有其他选项可以存储数据(从组件的角度来看)。方法,可以公平地假设,create
必须调用方法才能存储数据。因此verify(yourComponent).create()
是证明你的代码执行是正确的。当然,这需要知道使用了特定的 API(提供 create
方法),因此它是一种白盒测试。
还有其他用例:
调用次数(即传递了 10 个项目,假设添加了 10 个项目:
verify(list, times(10)).add(any(Item.class))
捕获参数,即断言发生了某种转换或传递了正确的参数,并且您需要访问该参数
ArgumentCaptor<ExpectedType> captor = ArgumentCaptor.forClass(ExpectedType.class); verify(theApi).apiMethod(captor.capture()); ExpectedType passedParam = captor.getValue();
验证方法是否未被调用(即在某些条件下,结合积极的测试)
验证是否已调用具有特定参数的方法(= 已发送特定消息):
verify(subject).method(eq("param1"), eq("param2"))
但所有这些都归结为指定 API 的使用,以便指定哪些消息应发送到另一个组件或系统,而不是指定测试中实现的每一行(这毫无意义)。
关于unit-testing - 在mockito中验证的想法是什么以及我什么时候应该使用它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37511538/