Mockito verify the last call on a mocked object

岁酱吖の 提交于 2019-12-21 05:41:51

问题


I have a bit of logic that needs to be tested such as:

{
    ...
    A.add("1");
    ...
    A.add("what ever");
    ...
    A.add("2");
    A.delete("5");
    ...
}

I have already mocked A in my test and I can test the add method is called once on argument ("2") such as:

Mockito.verify(mockedA).add("2");

My question is how can I test if I can verify the last call on method add is add("2") instead of other arguments.

Since the test above can't catch if somebody by accident adds another call such as add("3") in the last. Please notice that we don't care about other method invocations on A again afterwards. We also don't care about the times of the method called, the sequence of the methods called. The key point here is if we can verify the last true argument on a certain method of a certain mockedObject.

If you ask why do you need such functionality, I'd say in real world we might need to handle some logic that set something and the last set wins, and in order to avoid someone by accident set some other thing unexpected and I'd like to use our UT to catch this. And in order not to make the test too complex and neat, so I only expect to verify the last call on a certain method of a object instead verify something like order/noMoreInteractions/AtMostTimes and so on.


回答1:


About the order of the invocations

By default, Mockito.verify() doesn't matter of the invocation order.
To take it into consideration, wrap the mock in an InOrder instance and perform the invocation verification on this instance.

About the no more interations

If the mock is no more invoked after the methods that you want to verify, you could use Mockito.verifyNoMoreInteractions(Object... mocks) that checks if any of given mocks has any unverified interaction such as :

InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verifyNoMoreInteractions(mockedA);

If the mock may still be invoked after the methods that you want to verify, you could add after your verifies an invocation to verify(T mock, VerificationMode mode) by passing a VerificationMode that checks that at most 2 invocations were performed.

InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verify(mockedA, Mockito.atMost(2)).add(Mockito.anyString());

A warning about your think and this way of mocking

Since the test above can't catch if somebody by accident adds another call such as add("3") in the last.

Mockito provides a powerful and broad toolkit to work with mocks. Some features such as verify and more particularly verify that no more interaction was detected about a mock or a specific method of the mock make your test more complex to read and to maintain.
As well as, currently you want to check that the invocations on a mock were performed in a specific order. But you generally want to use these checks only as required that is according to the business/logic scenarios, not technical invocations.
For example supposing that in the tested method you have a case where for business reasons the mocked method is invoked 3 times and another case where the mocked method is invoked 2 times. It could make sense to check that it is only invoked 2 times and not more in the case with two expected invocations.
But in a general way, you should be cautious that your unit test doesn't overuse mocking verify that could look like as a assertion on the description of the flow and not a assertion on the behavior/logic.




回答2:


Thanks @staszko032, inspired by the ArgumentCaptor, instead of getAllValues and verify the sequence, we can use getValue of captor since captor's getValue always get the last true argument. We can do it like this:

    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
    Assert.assertEquals("2", captor.getValue());



回答3:


What this looks like to me is that you are mocking a data class. In my experience it's better to leave (stateful) data classes and mock (stateless) services. This way, you can verify that the method under test produces the correct data, rather than just verifying a series of invocations. Along with testdata builders (making it easy to instantiate your data classes with some default state, using builder pattern for instance), it becomes real easy to write tests.

If you do need to mock, the only way to test what you want is to use InOrder, and verify each of the invocations on the mock, and end with verifyNoMoreInteractions.



来源:https://stackoverflow.com/questions/50503729/mockito-verify-the-last-call-on-a-mocked-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!