benjamin
benjamin

Reputation: 1066

Mockito: How do you verify the group order of certain groups of method calls?

I'm using Mockito to verify orders of method calls with the InOrder object. But I am not interested in a total ordering of the calls, only that a certain group of method calls all happen before some other methods are invoked. For example like this

@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();
}

But this test does test too much, since it tests the order of the Foo instances. But I'm only interested in the order of the different methods. In fact I want underTest to not differentiate the instances of Foo, it may have an internal order on them or not, so it does not matter in which order the foos are called. I'd like to keep that as an implementation detail.

But it is important that doThisFirst() has been called on all of the foos before beforeDoingThis() is invoked on any other foo. Is it possible to express that with Mockito? How?

Upvotes: 15

Views: 8230

Answers (2)

Thirler
Thirler

Reputation: 20760

You can access the internals by implementing your own verification mode (thanks to this answer for teaching me, my code is based on it). The implementation is not complete, but you'll get the idea.

Unfortunately Mockito doesn't document this interface, they probably consider it internal (so it might not be 100% stable in future releases).

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

and then

// 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;
    }
}

Upvotes: 3

EdC
EdC

Reputation: 2349

Mockito verifies the order across all the mocks that were passed to the inorder function. So if you don't want to verify the order of the foos you need to create two seperate in-orders. i.e.

@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();
}

Upvotes: 8

Related Questions