Well it looks like Mockito is a bit inconvenient here. It detects the method call and logs it (use mock(MyOutput.class, withSettings().verboseLogging());
to enable logging), but it stores the reference to the array you're passing and thus is influenced when you mutate the array. It then thinks the method call was send(42, [98])
rather than send(42, [97])
.
A possible way to work with that is to use the expectations you've mentioned. For example you can use a counter and increment it if a call matched the expectations (it is really just a workaround and rather nasty):
MyOutput mock = mock(MyOutput.class, withSettings().verboseLogging());
Main subject = new Main(mock);
AtomicInteger correctCallsCounter = new AtomicInteger(0);
doAnswer(invocation -> correctCallsCounter.incrementAndGet()).when(mock).send(eq(42), aryEq(new byte[]{'a'}));
doAnswer(invocation -> correctCallsCounter.incrementAndGet()).when(mock).send(eq(55), aryEq(new byte[]{'b'}));
subject.myMethod();
assertThat(correctCallsCounter.get(), is(2));
It works, because doAnswer
is triggered when the call happens and when the byte array hasn't been changed yet.
The big downside of this workaround is, that it only works with void
methods. If send
would return "something", then I currently don't see a way to work around that.
Well and the other one is that this is obviously a rather nasty workaround.
So I would suggest to refactor your code a bit (use a new array) if that is possible. That would avoid these issues here.
If your send
method would indeed return something and your myMethod
method would rely on it, then you would usually mock it this way (send
is expected to return a String in this example):
when(mock.send(eq(55), aryEq(new byte[]{'b'}))).thenReturn("something");
In order to still use the above mentioned workaround, you could change the doAnswer
method to increment your counter and return your String (which you would mock anyway, thus it isn't that bad):
doAnswer(invocation -> {
correctCallsCounter.incrementAndGet();
return "something";
}).when(mock).send(eq(42), aryEq(new byte[]{'a'}));