Reputation: 8500
I'm trying to test the method on mocked object getting called in the expected order or not. Below is the simplified example:
@Test
public void test() {
List<String> mockedList = Mockito.mock(List.class);
for (int i = 0; i < 5; i++) {
mockedList.add("a");
mockedList.add("b");
mockedList.add("c");
}
// I want only this to pass.
InOrder inOrder1 = Mockito.inOrder(mockedList);
inOrder1.verify(mockedList).add("a");
inOrder1.verify(mockedList).add("b");
inOrder1.verify(mockedList).add("c");
// I want this to fail.
InOrder inOrder2 = Mockito.inOrder(mockedList);
inOrder2.verify(mockedList).add("c");
inOrder2.verify(mockedList).add("b");
inOrder2.verify(mockedList).add("a");
}
Although the verifying order (c -> b -> a
) is different from the invocation order (a -> b -> c
), this test passes. This is because Mockito verifies if method2 called anywhere AFTER method1, but not immediately (i.e., no other method called in between). As I'm adding elements multiple times, this is very much possible. Which means, Mockito InOrder passes for b -> a -> c -> a -> c -> b -> c -> b -> a ...
But I want this to fail, and make sure the order is always a -> b -> c -> a -> b -> c -> a -> b -> c ...
Update: Proper way to verify is to verify the order same number of iterations (summary of accepted answer):
for (int i = 0; i < 5; i++) {
inOrder1.verify(mockedList).add("a");
inOrder1.verify(mockedList).add("b");
inOrder1.verify(mockedList).add("c");
}
// fail the test if we missed to verify any other invocations
inOrder1.verifyNoMoreInteractions();
Upvotes: 4
Views: 4960
Reputation: 140427
A non answer here: you are going down the wrong path (at least for the given example):
Meaning: when you create an "API", you want to achieve "easy to use, hard to mis-use". An API that requires methods to be called in a certain order doesn't achieve that. Thus: feeling the need to check for order programmatically could be an indication that you are doing "the wrong thing". You should rather design an API that "does the right thing" instead of expecting users of your code to do that for you.
Beyond that: when you are testing lists, you absolutely do not want to use mocking in the first place.
You want to make sure that elements get added to a list in a specific order? Then a simple
assertThat(actualList, is(expectedList));
is the one and only thing your test should check for!
Meaning: instead of testing an implementation detail (add()
gets called with this and that parameter, in this and that order), you simply check for the observable outcome of that operation. You don't care in which order things get added, and maybe re-setted and updated, you only care for the final result!
Given the comment by the OP: when you have to process certain calls/objects "in order", then you should design an interface that allows you communicate that intent. You are only testing your intent via unit tests. That is of course a good start, but not sufficient!
Basically, there are two concepts that could work for you:
Command
class (that executes "something"), and then create different subclasses for each required activity. And then your processor simply creates a List<Command>
. And now testing boils down to: generating such a sequence, and checking that each entry is of a given type.Upvotes: 0
Reputation: 4044
The thing is that you need to add
inOrder.verifyNoMoreInteractions();
With your loop you generate calls like
When you then check
inOrder.verify(mockedList).add("b");
inOrder.verify(mockedList).add("c");
inOrder.verify(mockedList).add("a");
It matches the calls (add(b), add(c), add(a)). The other calls are not checked.
So I think you have to options: 1) verify all calls a, b, c, a, b, c 2) verify that no more interactions happen to your mock
BTW if you change the verification to
inOrder.verify(mockedList).add("c");
inOrder.verify(mockedList).add("b");
inOrder.verify(mockedList).add("a");
it will fail as it does not match the calls :-)
Upvotes: 3