logo
Solutionunittest

Mockito verification

Views: 346 Created: 2019-01-04 Read time: 3 minutes
Post Preview
Tags:

1)     Preface

Behaviour verification of mocks is one of the core features of Mockito. It enables the developer to perform additional checks, outside of the traditional value/object state testing. In this post, we will go through common use cases. There are these moments where there is a need to use timeouts, ordered verification or lazy verification. Thes are advanced techniques and have posts of their own.

 

Note
Note

 

2)     Mockito verify: single method invocation

Let's start out with a basic example where would like to verify that a particular method has been called precisely once with given parameters. This time we will try to book a table at our favourite restaurant.

 

SUT Code


public void bookTable(Customer customer){
    manager.answerCall(customer);

    Table table = manager.findFreeTable(restaurantSystem);

    if(table == null){
        restaurantSystem.notifyCustomerWhenTablesAvailable(customer);
        manager.appologiseAndConfirmNotification(customer);

        return;
    }

    restaurantSystem.bookTable(table);
    manager.confirmBooking(customer);
}

In this SUT method we are:

      (L3):  Answering a call from a customer.

      (L5):  Manager checks the system for any tables available.

      (L7-10):  If none are available, the system records to notify the customer when any table is free. The manager informs the customer.

      (L14,15):  If there are tables available, the system performs the reservation and manager confirm the booking with the customer.

 

We would like to test that when there is a table available, the system performs the booking and the customer is notified about it. Both interactions must happen only once:

 

Test Code


@InjectMocks private RestaurantController restaurantControllerSUT;
@Mock private RestaurantSystem restaurantSystemMock;
@Mock private Manager managerMock;

@Test
public void shouldBookATable() throws Exception{
    // Arrange
    Table tableToBook = new Table();
    Customer customer = new Customer();
    when(managerMock.findFreeTable(restaurantSystemMock))
            .thenReturn(tableToBook);

    // Act
    restaurantControllerSUT.bookTable(customer);

    // Assert
    verify(restaurantSystemMock).bookTable(tableToBook);
    verify(managerMock, times(1)).confirmBooking(customer);
}

In this test code we are:

      (L9-12):  Preparing the system for a positive booking request.

      (L15):  Invoking the SUT.

      (L18,19):  Making sure that RestaurantSystem booked the proper table and that the Manager has confirmed the booking with the Customer.

 

Tip
Tip

 

3)     Mockito verify: no interactions have occured

Let's take another look at the table booking example and try to go through a scenario when there are no free tables. Damn, why does this happen so often in my favourite joint!

 

Test Code


@Test
public void shouldApologiseAndNotifyWhenNoFreeTables() throws Exception{
    // Arrange
    Customer customer = new Customer();
    when(managerMock.findFreeTable(restaurantSystemMock))
            .thenReturn(null);

    // Act
    restaurantControllerSUT.bookTable(customer);

    // Assert
    verify(restaurantSystemMock).notifyCustomerWhenTablesAvailable(customer);
    verify(managerMock).appologiseAndConfirmNotification(customer);

    verify(restaurantSystemMock, never()).bookTable(any(Table.class));
    verify(managerMock, times(0)).confirmBooking(customer);
}

In this test code we are:

      (L6):  Making sure that the restaurantSystemMock will not find any free tables.

      (L16,17):  Verify that restaurantSystemMock has never been instructed to book a table and that the managerMock has not confirmed the booking with the customer.

 

Tip
Tip

 

4)     Mockito verify: multiple interactions

Now we will go through a scenario where would like to make sure that a certain interaction has happened n number of times. This time we will try to accept the payment for a bill from our customer.

 

SUT Code


public Bill processBill(Customer customer, Waiter waiter, Order order){
    Bill bill = waiter.prepareBillForOrder(order);
    Iterator<CreditCard> creditCards = customer.prepareToPay();

    while(!bill.paid()){
        if(creditCards.hasNext()){
            CreditCard creditCard = creditCards.next();

            boolean transactionSuccessful = waiter.performTransaction(bill, creditCard);

            if(transactionSuccessful){
                bill.setPaid(true);
                break;
            }else{
				waiter.informTransactionNotAccepted(customer);
			}
		}else{
            throw new RuntimeException("Customer cannot pay");
        }
    }

    return bill;
}

In this SUT method we are:

      (L3):  Preparing the bill for our customer.

      (L4):  Customer prepares his credit cards to pay.

      (L6):  Until the bill is paid we try to accept the payment from the customer.

      (L16):  Waiter informs the customer that his card was not accepted.

      L(19): We all had that.. none of our cards can simply pass through the system.

 

Let's try to write a test where the customer credit card payment will be successful but only on the third attempt.

 

Test Code


@Test
public void shouldProcessBillWhenManyCreditCardsAttempted() throws Exception{
    // Arrange
    Bill bill = new Bill();
    Order orderDummy = new Order();
    Waiter waiterMock = mock(Waiter.class);
    Customer customer = new Customer();

    when(waiterMock.prepareBillForOrder(orderDummy)).thenReturn(bill);

    when(waiterMock.performTransaction(eq(bill), any(CreditCard.class)))
            .thenReturn(false)
            .thenReturn(false)
            .thenReturn(true);

    // Act
    Bill resultBill = restaurantControllerSUT.processBill(customer, waiterMock, orderDummy);

    // Assert
    assertThat(resultBill.paid()).isTrue();

    verify(waiterMock, times(3)).informTransactionNotAccepted(customer);
}

In this test method we are:

      (L12):  Making sure that the first two card transactions will not be successful. The third attempt will be.

      (L23):  Verifying that the waiter has informed the customer each time his card was not accepted.

 

5) Mockito ArgumentCaptor: verify exact state of passed value

There are cases where a simple check of a number of invocations is not enough. Let's go back to our previous transaction processing test and try to add another level of detail to it. This time, apart from the number of invocations we also want to make sure that the CreditCard passed to each transaction processing method was different.

We will take advantage of the ArgumentCaptor feature which Mockito offers us to use.

 

Reference
Reference
unittest
Mockito argument capturing

 

Test Code


@Test
public void shouldProcessDifferentCardAfterEachTransactionFail() throws Exception{
    // Arrange
    // the same as in previous test

    // Act
    Bill resultBill = restaurantControllerSUT.processBill(customer, waiterMock, orderDummy);

    // Assert
    ArgumentCaptor<CreditCard> creditCardCaptor = ArgumentCaptor.forClass(CreditCard.class);

    verify(waiterMock, times(3)).performTransaction(eq(bill), creditCardCaptor.capture());

    List<CreditCard> capturedCards = creditCardCaptor.getAllValues();
    Set<CreditCard> creditCardSet = new HashSet<>(capturedCards);

    assertThat(creditCardSet.size()).isEqualTo(3);
}

In this test method we are:

      (L5):  Perform the same set-up as in the previous test method.

      (L11):  Create an ArgumentCaptor that will allow us to capture the passed CreditCard objects during the runtime of the test.

      (L13):  We verify that the performTransaction method has been called 3 times and we pass in the creditCardCaptor.capture() method that will do the capturing.

      (L15):  We retrieve all the captures CreditCards using the creditCardCaptor.getAllValues() method.

      (L16-18):  We add them all to a Set and assert that the size is still the same, meaning that all of them were unique.

 

Note
Note

 

6)     Conclusion

 

Summary

 

Mockito's verify feature is the by far it's most crucial functionality just after stubbing. It adds a massive weapon to our automated testing arsenal kit that we can use on many fronts. From the day to day missions to those complex non-standards ones. Thanks to it, we can be 100% sure that everything is up to measure!

 

Need more insight?
Repository
Repository
Glossary
Glossary
Tags:
Reference
You may also like:
mockito-ordered-verification
Mockito ordered verification
test-method-naming
Test method naming
mockito-no-interactions
Mockito no interactions
Comments
Be the first to comment.
Leave a comment