I have following code I want to test:
public class MessageService {
private MessageDAO dao;
public void acceptFromOffice(Message message) {
message.setStatus(0);
dao.makePersistent(message);
message.setStatus(1);
dao.makePersistent(message);
}
public void setDao (MessageDAO mD) { this.dao = mD; }
}
public class Message {
private int status;
public int getStatus () { return status; }
public void setStatus (int s) { this.status = s; }
public boolean equals (Object o) { return status == ((Message) o).status; }
public int hashCode () { return status; }
}
I need to verify, that method acceptFromOffice really sets status to 0, than persist message, then chage its status to 1, and then persist it again.
With Mockito, I have tried to do following:
@Test
public void testAcceptFromOffice () throws Exception {
MessageDAO messageDAO = mock(MessageDAO.class);
MessageService messageService = new MessageService();
messageService.setDao(messageDAO);
final Message message = spy(new Message());
messageService.acceptFromOffice(message);
verify(messageDAO).makePersistent(argThat(new BaseMatcher<Message>() {
public boolean matches (Object item) {
return ((Message) item).getStatus() == 0;
}
public void describeTo (Description description) { }
}));
verify(messageDAO).makePersistent(argThat(new BaseMatcher<Message>() {
public boolean matches (Object item) {
return ((Message) item).getStatus() == 1;
}
public void describeTo (Description description) { }
}));
}
I actually expect here that verification will verify calling twice of makePersistent method with a different Message object’s state. But it fails saying that
Argument(s) are different!
Any clues?
Testing your code is not trivial, though not impossible. My first idea was to use ArgumentCaptor, which is much easier both to use and comprehend compared to ArgumentMatcher. Unfortunately the test still fails – reasons are certainly beyond the scope of this answer, but I may help if that interests you. Still I find this test case interesting enough to be shown (not correct solution):
Unfortunately the working solution requires somewhat complicated use of Answer. In a nutshell, instead of letting Mockito to record and verify each invocation, you are providing sort of callback method that is executed every time your test code executes given mock. In this callback method (
MakePersistentCallbackobject in our example) you have access both to parameters and you can alter return value. This is a heavy cannon and you should use it with care:The example is not complete, but now the test succeeds and, more importantly, fails when you change almost anything in CUT. As you can see
MakePersistentCallback.answermethod is called every time mockedmessageService.acceptFromOffice(message)is called. Insidenasweryou can perform all the verifications you want.NB: Use with caution, maintaining such tests can be troublesome to say the least.