Mockito:如何在一个具有不同参数的模拟器上按顺序调用一个方法

时间:2013-08-21 21:33:59

标签: java mockito

我想测试使用不同参数调用mock的方法:

我尝试使用以下代码:

    InOrder inOrder = inOrder(myobject);
    inOrder.verify(myobject).println(any(String.class));
    inOrder.verify(myobject).println(any(String.class));
    inOrder.verify(myobject).println("");
    inOrder.verify(myobject).println("myfolder");
    inOrder.verify(myobject).println("");
    inOrder.verify(myobject).println(System.getProperty("user.home"));

然而,这似乎不起作用,因为它给我一个错误说

    inOrder.verify(myobject).println(any(String.class));

已被召唤8次。这是正确的,但它无法解决订单。

我想查一下:

  The println method of `myobject` is first called with any string parameter
  Then it is called with any string parameter again
  Then it is called by an empty string
  Then it is called by string "myfolder"
  ......

我怎样才能做到这一点?

编辑:

错误信息是:

org.mockito.exceptions.verification.VerificationInOrderFailure: 
Verification in order failure:
printWriter.println(<any>);
Wanted 1 time:
-> at com.mycompany.MyUnitTest.mytest(MyrUnitTest.java:107)
But was 8 times. 

3 个答案:

答案 0 :(得分:5)

使用参数captor捕获所有println调用中的参数,然后检查您感兴趣的每个捕获值。

@Captor ArgumentCaptor<String> stringCaptor;

// ...

@Test public void myTest() {

    // ...

    verify(myobject, 6).println(stringCaptor.capture());
    assertEquals("", stringCaptor.getAllValues()[2]);
    assertEquals("myfolder", stringCaptor.getAllValues()[3]);
    assertEquals("", stringCaptor.getAllValues()[4]);    
    assertEquals(System.getProperty("user.home"), stringCaptro.getAllValues()[5]);

答案 1 :(得分:3)

David Wallace的解决方案是我所知道的最好的解决方案,使用Mockito,但请记住,嘲笑并不总是适合这项工作的工具。

如果可以,而不是模拟,则传递PrintWriter(ByteArrayOutputStream)并检查ByteArrayOutputStream是否与您期望的输出相匹配。

@Test public void yourTest() {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  PrintWriter writer = new PrintWriter(baos);
  systemUnderTest.doThing(writer);

  assertTrue(writer.toString().endsWith(
      "\n\nmyfolder\n\n" + System.getProperty(user.home) + "\n"));
}

这也可能更接近你实际测试的逻辑,即输出看起来像你期望的那样,而不是以完全正确的顺序调用方法。然后,您可以自由地重构任何您想要的方式,包括切换到MessageFormatter模板,或者将换行符构建到StringBuilder并调用println一次。您还与使用任何其他printprintln()电话的任何人隔离,否则会导致基于Mockito的测试。

您还可以使用正则表达式PatternScanner来验证正确性,具体取决于您的需求的具体情况。如果您需要以编程方式构建预期的字符串,那么Pattern.quote可以帮助您逃避正则表达式子字符串(与此处user.home一样)。

答案 2 :(得分:1)

嗯,这个答案不是太笼统,也不优雅。

对我来说,似乎问题是由any(String.class)贪婪造成的,也就是说,它匹配所有类型的字符串。所以,我试图制作一个匹配所有类型字符串的匹配器,除了少数例外:"" or "myfolder" or System.getProperty("user.home")。代码是:

import static org.mockito.AdditionalMatchers.*;

inOrder.verify(myobject, times(2)).println(
            and(anyString(), not(
                    or(eq(""), or(eq("myfolder"), eq(System.getProperty("user.home")))))));

将其格式化为可读是一种挑战(出于某种神秘的原因,我甚至无法将and(...)提取到局部变量,因为它会导致模拟的奇怪的运行时异常,我不能在外面使用匹配器存根或验证)。