unit-testing - 在mockito中验证的想法是什么以及我什么时候应该使用它

标签 unit-testing mocking mockito

据我了解,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);
    }
}

测试验证当调用UserServicecreateUser 方法时,是否调用UserDAOcreate 方法。看起来很荒谬。如果我更改 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/

相关文章:

android - 在 Android Studio 中运行所有单元测试

java - Mockito/PowerMocktio doNothing for none void 方法

objective-c - 如何使用 OCMock for iOS 模拟私有(private)属性?

unit-testing - 如何从mstest命令行在播放列表文件中运行测试

java - 在不继承抽象类的情况下模拟对抽象类的公共(public)方法的调用,最好使用 mockito

java - Mockito inOrder.verify() 使用模拟作为函数参数失败

mocking - 我可以模拟带有 juni5 和 mockito 或 easymock 的静态方法吗?

symfony - 如何在 phpunit 功能测试中模拟 symfony Controller 的自动连接服务?

unit-testing - angularjs Controller 测试 : unsatistifed post request

mocking - 有人让痣正常工作了吗?