【问题标题】:Using Mockito, how do I verify a method was a called with a certain argument?使用 Mockito,我如何验证一个方法是用某个参数调用的?
【发布时间】:2012-08-03 20:25:51
【问题描述】:

我正在使用 Mockito 1.9.0。我将如何验证一个方法是否只被调用了一次,并且传递给它的一个字段是否包含某个值?在我的 JUnit 测试中,我有

@Before
public void setupMainProg() { 
    // Initialize m_orderSvc, m_opportunitySvc, m_myprojectOrgSvc
    ...
    m_prog = new ProcessOrdersWorker(m_orderSvc, m_opportunitySvc, m_myprojectOrgSvc);
}   // setupMainProg

@Test
public void testItAll() throws GeneralSecurityException, IOException { 
    m_prog.work();  
}

方法“work”调用方法“m_orderSvc”(传递给对象的参数之一)。 “m_orderSvc”又包含一个成员字段“m_contractsDao”。我想验证“m_contractsDao.save”是否被调用了一次,并且传递给它的参数是否包含某个值。

这可能有点令人困惑。让我知道如何澄清我的问题,我很乐意这样做。

【问题讨论】:

    标签: java mocking mockito


    【解决方案1】:

    首先,您需要创建一个模拟 m_contractsDao 并进行设置。假设类是 ContractsDao:

    ContractsDao mock_contractsDao = mock(ContractsDao.class);
    when(mock_contractsDao.save(any(String.class))).thenReturn("Some result");
    

    然后将 mock 注入 m_orderSvc 并调用您的方法。

    m_orderSvc.m_contractsDao = mock_contractsDao;
    m_prog = new ProcessOrdersWorker(m_orderSvc, m_opportunitySvc, m_myprojectOrgSvc);
    m_prog.work(); 
    

    最后,验证 mock 是否被正确调用:

    verify(mock_contractsDao, times(1)).save("Parameter I'm expecting");
    

    【讨论】:

    • 仅供参考,您可以省略, times(1),因为它始终是隐含的,除非您添加一个量词来指定不是一次性的东西。而不是any(String.class),有一个稍微方便一点的anyString()
    • 还值得注意的是,在verify 之后传递给方法的参数是使用equals 与实际测试期间传递的参数进行比较的。所以,无论是什么方法(mamboking 示例中的save 方法),请考虑每个参数的type,以及与equals 的比较是否是您真正想要的。如果您希望使用 equals 以外的其他内容测试参数,则需要某种 ArgumentMatcher(可能是 Kevin Welker 的回答中的 ArgumentCaptor)。
    • 你如何指定一次,而不是两次或更多? @KevinWelker 的评论说它是隐含的,但不确定它是否意味着一次,或者至少一次。
    • 不是传递我期望的确切参数,有没有办法代替可能传递给方法的参数传递谓词?例如。 verify(mock_contractsDao, times(1)).save((String s) -> s.length() == 23);?
    • 我还没有在 Mockito 2.x 中尝试过任何东西,但你可能会在新的 ArgumentMatcher 中找到你想要的东西。此语法可能不正确,但在 Mockito 2.x 下,以下可能接近您想要的:verify(mock_contractsDao).save(argThat(s->s.length==23));
    【解决方案2】:

    基于 Mamboking 的回答:

    ContractsDao mock_contractsDao = mock(ContractsDao.class);
    when(mock_contractsDao.save(anyString())).thenReturn("Some result");
    
    m_orderSvc.m_contractsDao = mock_contractsDao;
    m_prog = new ProcessOrdersWorker(m_orderSvc, m_opportunitySvc, m_myprojectOrgSvc);
    m_prog.work(); 
    

    解决您的请求以验证参数是否包含某个值,我可以假设您的意思是参数是一个字符串,并且您想测试字符串参数是否包含子字符串。为此,您可以这样做:

    ArgumentCaptor<String> savedCaptor = ArgumentCaptor.forClass(String.class);
    verify(mock_contractsDao).save(savedCaptor.capture());
    assertTrue(savedCaptor.getValue().contains("substring I want to find");
    

    如果这个假设是错误的,并且save() 的参数是某种集合,那么它只会略有不同:

    ArgumentCaptor<Collection<MyType>> savedCaptor = ArgumentCaptor.forClass(Collection.class);
    verify(mock_contractsDao).save(savedCaptor.capture());
    assertTrue(savedCaptor.getValue().contains(someMyTypeElementToFindInCollection);
    

    如果您知道如何使用 Hamcrest 匹配器,您也可以查看 ArgumentMatchers

    【讨论】:

      【解决方案3】:

      这是更好的解决方案:

      verify(mock_contractsDao, times(1)).save(Mockito.eq("Parameter I'm expecting"));
      

      【讨论】:

      • 这在处理非原始类型时会更好。
      • 这也有效,如果你有其他参数是匹配器,如 any()、anyOrNull() 等,你也必须使用 eq()。你可以同时使用匹配器和文字。跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-18
      • 2021-07-24
      • 2017-01-20
      • 1970-01-01
      • 2016-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多