【问题标题】:What is the idea of verify in mockito and when should I use it在 mockito 中验证的想法是什么,我应该什么时候使用它
【发布时间】:2016-05-29 15:13:48
【问题描述】:

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

测试验证 UserDAOcreate 方法在 UserServicecreateUser 方法被调用时被调用。看起来很荒谬。如果我以不调用 UserDAO 方法的方式更改 UserService 的实现,即使实现正确,我的测试也会失败。

我承认,在某些情况下,可能需要验证该方法被调用的确切次数,但这种情况并不常见。

我很可能不理解 verify 的概念,而且它不是 mockito 特有的功能。你能用简单的话解释一下,什么时候使用它真的有意义。

【问题讨论】:

    标签: unit-testing mocking mockito


    【解决方案1】:

    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 的使用,以指定哪些消息应该发送到另一个组件或系统,而 不是 指定测试中实现的每一行(这将毫无意义)。

    【讨论】:

      【解决方案2】:

      UserServiceTest 的全部意义在于测试它的实现。所以是的,您确实想验证您确实调用了UserDAO 接口的create 方法。

      【讨论】:

        猜你喜欢
        • 2011-01-18
        • 2011-08-18
        • 2017-03-21
        • 2010-09-05
        相关资源
        最近更新 更多