Mockito: Как вы проверяете групповой порядок определенных групп вызовов методов?

Я использую Mockito для проверки заказов вызовов методов с объектом InOrder. Но меня не интересует полное упорядочение вызовов, только то, что определенная группа вызовов метода все происходит до вызова других методов. Например, например

@Test
public void testGroupOrder() {
    Foo foo1 = mock(Foo.class);
    Foo foo2 = mock(Foo.class);
    Bar underTest = new Bar();
    underTest.addFoo(foo1);
    underTest.addFoo(foo2);

    underTest.fire()

    InOrder inOrder = inOrder(foo1,foo2);

    inorder.verify(foo1).doThisFirst();
    inorder.verify(foo2).doThisFirst();

    inorder.verify(foo1).beforeDoingThis();
    inorder.verify(foo2).beforeDoingThis();
}

Но этот тест слишком много проверяет, так как он проверяет порядок экземпляров Foo. Но меня интересует только порядок разных методов. На самом деле я хочу, чтобы underTest не различал экземпляры Foo, у них может быть внутренний порядок или нет, поэтому не имеет значения, в каком порядке вызывается foos. Я хотел бы сохранить это как деталь реализации.

Но важно, чтобы doThisFirst() был вызван во всех foos до того, как beforeDoingThis() вызывается на любом другом foo. Можно ли выразить это с помощью Мокито? Как?

Ответ 1

Mockito проверяет порядок по всем mocks, которые были переданы в функцию inorder. Поэтому, если вы не хотите проверять порядок foos, вам нужно создать два отдельных in-orders. то есть.

@Test
public void testGroupOrder() {
    Foo foo1 = mock(Foo.class);
    Foo foo2 = mock(Foo.class);
    Bar underTest = new Bar();
    underTest.addFoo(foo1);
    underTest.addFoo(foo2);

    underTest.fire()

    InOrder inOrderFoo1 = inOrder(foo1);
    inOrderFoo1.verify(foo1).doThisFirst();
    inOrderFoo1.verify(foo1).beforeDoingThis();

    InOrder inOrderFoo2 = inOrder(foo2);
    inOrderFoo2.verify(foo2).doThisFirst();
    inOrderFoo2.verify(foo2).beforeDoingThis();
}

Ответ 2

Вы можете получить доступ к внутренним компонентам, выполнив свой собственный режим проверки (благодаря этому ответу для обучения меня, мой код основан на нем). Реализация не завершена, но вы получите эту идею.

К сожалению, Mockito не документирует этот интерфейс, они, вероятно, считают его внутренним (поэтому он не может быть на 100% стабильным в будущих выпусках).

verify(foo1, new DoFirst()).doThisFirst();
verify(foo2, new DoFirst()).doThisFirst();
verify(foo1, new DoSecond()).beforeDoingThis();
verify(foo1, new DoSecond()).beforeDoingThis();

а затем

// Set to true when one 
boolean secondHasHappened = false; 

// Inner classes so they can reach the boolean above.
// Gives an error of any DoSecond verification has happened already.
public class DoFirst implements VerificationMode {
   public void verify(VerificationData data) {
      List<Invocation> invocations = data.getAllInvocations()
      InvocationMatcher matcher = data.getWanted();
      Invocation invocation = invocations.get(invocations.size() - 1);
      if (wanted.matches(invocation) && secondHasHappened) throw new MockitoException("...");
   }
}

// Registers no more DoFirst are allowed to match.
public class DoSecond implements VerificationMode {
    public void verify(VerificationData data) {
       List<Invocation> invocations = data.getAllInvocations()
       InvocationMatcher matcher = data.getWanted();
       Invocation invocation = invocations.get(invocations.size() - 1);
       if (!wanted.matches(invocation)) secondHasHappened = true;
    }
}