5

I want to test a method of a mock is called in order using different parameters:

I tried to use the following code:

    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"));

However, this does not seem to work as it gave me an error says

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

has been called for 8 times. This is correct through, but it fails to address the order.

I want to check:

  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"
  ......

How can I achieve this?

EDIT:

Error message is:

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. 
4

3 回答 3

5

使用参数捕获器捕获对 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]);
于 2013-08-22T00:35:18.240 回答
3

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

如果可以,而不是模拟,传递 aPrintWriter(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此处所做的那样),可以帮助您转义正则表达式子字符串。

于 2013-08-22T00:01:18.153 回答
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(...)到局部变量,因为它会导致来自 mockito 的奇怪运行时异常,我无法在存根或验证之外使用匹配器)。

于 2013-08-21T22:24:24.400 回答