In this recipe, we will verify that a set of methods get executed in the specified order.
For this recipe, our system under test will be TaxUpdator
which is a simplified version of a facade that calls the TaxService
methods (let's assume that it is a web service) to update tax-related data and perform a series of tax transfers. Let's assume that this web service is a legacy, a badly-written system, and we have to synchronously call it in a precisely defined sequence.
Let's take a look at the implementation of the TaxUpdator
class:
public class TaxUpdator { public static final int TAX_FACTOR = 100; private final TaxService taxService; public TaxUpdator(TaxService taxService) { this.taxService = taxService; } public void transferTaxFor(Person person) { taxService.updateTaxFactor(person, calculateTaxFactor(1)); taxService.transferTaxFor(person); taxService.transferTaxFor(person); taxService.updateTaxFactor(person, calculateTaxFactor(2)); taxService.transferTaxFor(person); } private double calculateTaxFactor(double ratio) { return TAX_FACTOR * ratio; } }
To verify whether the mock's method execution took place in a specified order, perform the following steps:
InOrder inOrder = Mockito.inOrder(mock1, mock2, … , mockn);
, where mock1
, mock2
, and mockn
are the objects that might be used in the verification process.inOrder.verify(mock).method(...); inOrder.verify(mock, verificationMode).method(...); inOrder.verifyNoMoreInteractions()
Let's check the JUnit test that verifies whether the web service's method has been called at most twice (see Chapter 1, Getting Started with Mockito, for the TestNG configuration):
@RunWith(MockitoJUnitRunner.class) public class TaxUpdaterTest { @Mock TaxService taxService; @InjectMocks TaxUpdater systemUnderTest; @Test public void should_update_tax_factor_and_transfer_tax_in_specified_order() { // given Person person = new Person(); // when systemUnderTest.transferTaxFor(person); // then InOrder inOrder = Mockito.inOrder(taxService); inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble()); inOrder.verify(taxService, times(2)).transferTaxFor(person); inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble()); inOrder.verify(taxService).transferTaxFor(person); } }
When you create the InOrder
object and define the desired order of execution, Mockito stores the expected order and then verifies it against the actual execution. During the iteration over the actual method invocations, depending on the passed verification mode (times(…)
, atLeast(…)
, and so on), Mockito marks either a single or multiple actual method executions as verified.
Let's try to depict this scenario using our test example. Having the inOrder.verify(taxService, times(2)).transferTaxFor(person);
verification in order means that we are asking Mockito to mark two subsequent invocations of the transferTaxFor(…)
method as verified and throw an exception if there were no such two subsequent calls.
The times(…)
method returns a verification mode that is not greedy, which means that it will verify subsequent calls only. Take a look at the following code:
inOrder.verify(taxService, times(2)).transferTaxFor(person); inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble()); inOrder.verify(taxService).transferTaxFor(person);
When Mockito goes past the first line, it will mark only two methods of transferTaxFor(…)
as verified. If there are any other transferTaxFor(…)
methods, Mockito will not mark them as verified. This will happen in the third line, where an additional verification takes place.
There is an interesting case of the calls(…)
method that behaves in a different manner from the analogous times(…)
and atLeast(…)
methods that return VerificationMode
. Let's have a look at the examples:
times(2)
: This method verifies that a method was executed exactly two times (it will fail if a method was invoked once or, for example, three times).atLeast(2)
: This method verifies that the method was executed at least twice (it will fail if a method was invoked once. It marks all the subsequent method executions as verified).calls(2)
: This method allows a non-greedy verification (check the There's more... section of this recipe for more information). If a method is executed three times, then calls(2)
will not fail, unlike the analogous times(3)
. Also, it will not mark the third invocation as verified, unlike atLeast(2)
.As stated in the previous section, there are verification modes that are greedy; they will mark all the matching method executions as verified.
Let's imagine the following scenario (the test is based on the previous example):
@Test public void should_fail_at_updating_second_tax_factor_in_specified_order_due_to_greedy_at_least() { // given Person person = new Person(); // when systemUnderTest.transferTaxFor(person); // then InOrder inOrder = Mockito.inOrder(taxService); inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble()); inOrder.verify(taxService, atLeastOnce()).transferTaxFor(person); inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble()); inOrder.verify(taxService).transferTaxFor(person); }
As you can see, the only difference between the tests is the following line (the difference is that we had times(2)
and now we have atLeastOnce()
):
inOrder.verify(taxService, atLeastOnce()).transferTaxFor(person);
This test won't succeed, which can seem very odd at first glance.
Let's have a look at the execution sequence of the system under the test's method in which we have all the mocked object's method executions:
taxService.updateTaxFactor(person, calculateTaxFactor(1)); taxService.transferTaxFor(person); taxService.transferTaxFor(person); taxService.updateTaxFactor(person, calculateTaxFactor(2)); taxService.transferTaxFor(person);
You may think that when we provide the atLeastOnce()
method, Mockito will mark all the subsequent executions of the transferTaxFor
method (in our case, there are two subsequent executions: lines two and three of the snippet) and then, the next verification step will be of the updateTaxFactor
method, in line four of the snippet.
Since atLeastOnce()
is greedy (atLeast()
is always greedy in the InOrder
verification), the following tasks take place:
transferTaxFor
method is verified against the AtLeast
verification mode, it marks all three transferTaxFor
methods as verified (lines two, three, and five).inOrder.verify(taxService).updateTaxFactor(eq(person), anyDouble())
.AtLeast
verification mode, we moved to the last execution of the transferTaxFor
method.updateTaxFactor
method.VerificationInOrderFailure
exception since there is no such method. The message will look more or less like the one shown as follows:Wanted but not invoked: taxService.updateTaxFactor( Person@183b1e8b, <any> ); -> at ExplainingTheGreedyAlgorithm.should_fail_at_updating_second_tax_factor_in_specified_order_due_to_greedy_at_least(ExplainingTheGreedyAlgorithm.java:56) Wanted anywhere AFTER following interaction: taxService.transferTaxFor( Person@183b1e8b );
If you are only interested in the fact that a given method gets executed in a precise order and you don't care about the rest, you just have to explicitly define only those interactions that you are interested in. In other words, you must use the following methods:
taxService.transferTaxFor(person); taxService.updateTaxFactor(person, taxFactor); taxService.transferTaxFor(person);
If you are only interested in the fact that the transferTaxFor
methods get executed one after another (ignore the updateTaxFactor
method), you would just have to write the following code:
InOrder inOrder = Mockito.inOrder(taxService); inOrder.verify(taxService).transferTaxFor(person); inOrder.verify(taxService).transferTaxFor(person);
3.137.212.124