Mockito Verify Example
In this article, I am going to show you an example of Mockito Verify. To test the state, we use assert
, likewise, to verify the test interactions, we use Mockito.verify
.
Below are my setup details:
- I am using Maven – the build tool
- Eclipse as the IDE, version Luna 4.4.1.
- TestNG is my testing framework, in case you are new to TestNG, please refer TestNG Maven Project Example.
- Add Mockito dependency to our
pom.xml
.
Let’s start verifying behavior!
1. System Under Test (SUT)
A test consists of the following three steps:
- Stubbing
- Running the SUT
- Verifying the behavior of SUT
In this example, the system under test is a Customer
who wants to withdraw some money. It has method withdraw(amount)
which collaborates with an AccountManager
to validate whether the customer has enough funds to withdraw.
If the customer has enough funds, the account manager will allow withdrawing money and return us the new balance. If the funds are not enough, it will throw NotEnoughFundsException
.
Ok, we know our SUT, we need to know the class we are going to stub. Well…can you make a guess? It is AccountManager
. In this example, we will stub its methods and verify how our SUT behaves in each case.
Before we start with our test cases, let’s go through each class.
The first one is an Account
class. It is empty, as the actual processing is handled only in AccountManager
Account:
package com.javacodegeeks.mockito; public class Account { }
Next is Customer
class. We already know its behavior but I just thought of adding couple of more points here:
Customer
relies onAccountManager
for withdrawing the amount. It has methodsetAccountManager(AccountManager)
which we will use to set the mock objectwithdraw(amount)
throwsNotEnoughFundsException
if funds are not enough. Else it will return the new balance after the withdrawal process.
Customer:
package com.javacodegeeks.mockito; public class Customer { private AccountManager accountManager; public long withdraw(long amount) throws NotEnoughFundsException { Account account = accountManager.findAccount(this); long balance = accountManager.getBalance(account); if (balance < amount) { throw new NotEnoughFundsException(); } accountManager.withdraw(account, amount); return accountManager.getBalance(account); } public void setAccountManager(AccountManager accountManager) { this.accountManager = accountManager; } }
NotEnoughFundsException:
package com.javacodegeeks.mockito; public class NotEnoughFundsException extends Exception { private static final long serialVersionUID = 1L; }
AccountManager
is responsible for managing the funds. Its methods are self-explanatory.
AccountManager:
package com.javacodegeeks.mockito; public interface AccountManager { long getBalance(Account account); long withdraw(Account account, long amount); Account findAccount(Customer customer); }
2. Verify Behavior
The first test case is withdrawButNotEnoughFunds
. We will try to withdraw more amount than is allowed. In the @BeforeMethod
called setupMock()
, we create the Customer
object, mock AccountManager
and set it to the Customer
. We stub the accountManager.findAccount(customer)
to return Account
object.
Few points to note about the test case:
- Stub
AccountManager
to return balance lesser than the amount requested.when(accountManager.getBalance(account)).thenReturn(balanceAmount200);
- Run the SUT method
Customer.withdraw(2000)
- Assert using
expectedExceptions
attribute thatNotEnoughFundsException
is thrown - Verify that certain methods from the mock object are called.
- Verify that
accountManager.findAccount(customer)
was called.verify(accountManager).findAccount(customer)
- Verify that
accountManager.withdraw(account, amount)
was never called.verify(accountManager, times(0)).withdraw(account, withdrawlAmount2000);
MockitoVerifyExample:
package com.javacodegeeks.mockito; import static org.mockito.Mockito.*; import org.mockito.InOrder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MockitoVerifyExample { private Customer customer; private AccountManager accountManager; private Account account; private long withdrawlAmount2000 = 2000L; @BeforeMethod public void setupMock() { customer = new Customer(); accountManager = mock(AccountManager.class); customer.setAccountManager(accountManager); account = mock(Account.class); when(accountManager.findAccount(customer)).thenReturn(account); } @Test(expectedExceptions=NotEnoughFundsException.class) public void withdrawButNotEnoughFunds() throws NotEnoughFundsException { long balanceAmount200 = 200L; p("Train getBalance(account) to return " + balanceAmount200); when(accountManager.getBalance(account)).thenReturn(balanceAmount200); printBalance(balanceAmount200); try { p("Customer.withdraw(" + withdrawlAmount2000 + ") should fail with NotEnoughFundsException"); customer.withdraw(withdrawlAmount2000); } catch (NotEnoughFundsException e) { p("NotEnoughFundsException is thrown"); verify(accountManager).findAccount(customer); p("Verified findAccount(customer) is called"); verify(accountManager, times(0)).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is not called"); throw e; } } private static void p(String text) { System.out.println(text); } private void printBalance(long balance) { p("Balance is " + balance + " and withdrawl amount " + withdrawlAmount2000); } }
Output:
Train getBalance(account) to return 200 Balance is 200 and withdrawl amount 2000 Customer.withdraw(2000) should fail with NotEnoughFundsException NotEnoughFundsException is thrown Verified findAccount(customer) is called Verified withdraw(account, 2000) is not called PASSED: withdrawButNotEnoughFunds
3. Verification by count
In the next example of Mockito Verify, we will review the test case withdrawal()
which defines the success scenario. Few points to note about the test case:
- We stub
accountManager.getBalance(customer)
to return enough balance for a successful withdrawal. - Since withdrawal was successful, we verify that
accountManager.withdraw(account, amount)
was called.verify(accountManager).withdraw(account, withdrawlAmount2000);
- We also verify the number of times a method was called. For example, in the case of successful withdrawal, we end up calling
accountManager.getBalance(account)
twice. Once before the withdrawal and the second time after the withdrawal.verify(accountManager, times(2)).getBalance(account)
- Account is determined only once.
verify(accountManager, atLeastOnce()).findAccount(customer);
MockitoVerifyExample:
package com.javacodegeeks.mockito; import static org.mockito.Mockito.*; import org.mockito.InOrder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MockitoVerifyExample { private Customer customer; private AccountManager accountManager; private Account account; private long withdrawlAmount2000 = 2000L; @BeforeMethod public void setupMock() { customer = new Customer(); accountManager = mock(AccountManager.class); customer.setAccountManager(accountManager); account = mock(Account.class); when(accountManager.findAccount(customer)).thenReturn(account); } @Test(expectedExceptions=NotEnoughFundsException.class) public void withdrawButNotEnoughFunds() throws NotEnoughFundsException { long balanceAmount200 = 200L; p("Train getBalance(account) to return " + balanceAmount200); when(accountManager.getBalance(account)).thenReturn(balanceAmount200); printBalance(balanceAmount200); try { p("Customer.withdraw(" + withdrawlAmount2000 + ") should fail with NotEnoughFundsException"); customer.withdraw(withdrawlAmount2000); } catch (NotEnoughFundsException e) { p("NotEnoughFundsException is thrown"); verify(accountManager).findAccount(customer); p("Verified findAccount(customer) is called"); verify(accountManager, times(0)).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is not called"); throw e; } } @Test public void withdraw() throws NotEnoughFundsException { long balanceAmount3000 = 3000L; p("Train getBalance(account) to return " + balanceAmount3000); when(accountManager.getBalance(account)).thenReturn(balanceAmount3000); printBalance(balanceAmount3000); p("Customer.withdraw(" + withdrawlAmount2000 + ")"); customer.withdraw(withdrawlAmount2000); verify(accountManager, times(2)).getBalance(account); p("Verified getBalance(account) is called twice"); verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is called just once"); verify(accountManager, atLeastOnce()).findAccount(customer); p("Verified findAccount(account) is called atleast once"); } private static void p(String text) { System.out.println(text); } private void printBalance(long balance) { p("Balance is " + balance + " and withdrawl amount " + withdrawlAmount2000); } }
Output:
Train getBalance(account) to return 3000 Balance is 3000 and withdrawl amount 2000 Customer.withdraw(2000) Verified getBalance(account) is called twice Verified withdraw(account, 2000) is called just once Verified findAccount(account) is called atleast once PASSED: withdraw
4. Verify Order
In our next test case withdrawAndVerifyOrder
, we verify the order in which methods were called using inOrder()
. To enforce the order verification, we need to call our verify()
methods on the InOrder
object.
order.verify(accountManager).findAccount(customer);
InOrder order = inOrder(accountManager);
MockitoVerifyExample:
package com.javacodegeeks.mockito; import static org.mockito.Mockito.*; import org.mockito.InOrder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MockitoVerifyExample { private Customer customer; private AccountManager accountManager; private Account account; private long withdrawlAmount2000 = 2000L; @BeforeMethod public void setupMock() { customer = new Customer(); accountManager = mock(AccountManager.class); customer.setAccountManager(accountManager); account = mock(Account.class); when(accountManager.findAccount(customer)).thenReturn(account); } @Test(expectedExceptions=NotEnoughFundsException.class) public void withdrawButNotEnoughFunds() throws NotEnoughFundsException { long balanceAmount200 = 200L; p("Train getBalance(account) to return " + balanceAmount200); when(accountManager.getBalance(account)).thenReturn(balanceAmount200); printBalance(balanceAmount200); try { p("Customer.withdraw(" + withdrawlAmount2000 + ") should fail with NotEnoughFundsException"); customer.withdraw(withdrawlAmount2000); } catch (NotEnoughFundsException e) { p("NotEnoughFundsException is thrown"); verify(accountManager).findAccount(customer); p("Verified findAccount(customer) is called"); verify(accountManager, times(0)).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is not called"); throw e; } } @Test public void withdraw() throws NotEnoughFundsException { long balanceAmount3000 = 3000L; p("Train getBalance(account) to return " + balanceAmount3000); when(accountManager.getBalance(account)).thenReturn(balanceAmount3000); printBalance(balanceAmount3000); p("Customer.withdraw(" + withdrawlAmount2000 + ")"); customer.withdraw(withdrawlAmount2000); verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is Called"); verify(accountManager, times(2)).getBalance(account); p("Verified getBalance(account) is called twice"); verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is called just once"); verify(accountManager, atLeastOnce()).findAccount(customer); p("Verified findAccount(account) is called atleast once"); } @Test public void withdrawAndVerifyOrder() throws NotEnoughFundsException { long balanceAmount3000 = 3000L; p("Train getBalance(account) to return " + balanceAmount3000); when(accountManager.getBalance(account)).thenReturn(balanceAmount3000); printBalance(balanceAmount3000); p("Customer.withdraw(" + withdrawlAmount2000 + ")"); customer.withdraw(withdrawlAmount2000); p("Verify order of method calls"); InOrder order = inOrder(accountManager); order.verify(accountManager).findAccount(customer); p("Verified findAccount(account) is called"); order.verify(accountManager).getBalance(account); p("Verified getBalance(account) is called"); order.verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is called"); order.verify(accountManager).getBalance(account); p("Verified getBalance(account) is called one more time after withdrawl"); } private static void p(String text) { System.out.println(text); } private void printBalance(long balance) { p("Balance is " + balance + " and withdrawl amount " + withdrawlAmount2000); } }
Output:
Train getBalance(account) to return 3000 Balance is 3000 and withdrawl amount 2000 Customer.withdraw(2000) Verify order of method calls Verified findAccount(account) is called Verified getBalance(account) is called Verified withdraw(account, 2000) is called Verified getBalance(account) is called one more time after withdrawl PASSED: withdrawAndVerifyOrder
5. Unverified Interaction
In our last example, we will improve our previous test case withdrawAndVerifyOrder()
. We will call verifyNoMoreInteractions(accountManager)
in the end after verifying all the methods to make sure that nothing else was invoked on your mocks.
MockitoVerifyExample:
package com.javacodegeeks.mockito; import static org.mockito.Mockito.*; import org.mockito.InOrder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MockitoVerifyExample { private Customer customer; private AccountManager accountManager; private Account account; private long withdrawlAmount2000 = 2000L; @BeforeMethod public void setupMock() { customer = new Customer(); accountManager = mock(AccountManager.class); customer.setAccountManager(accountManager); account = mock(Account.class); when(accountManager.findAccount(customer)).thenReturn(account); } @Test(expectedExceptions=NotEnoughFundsException.class) public void withdrawButNotEnoughFunds() throws NotEnoughFundsException { long balanceAmount200 = 200L; p("Train getBalance(account) to return " + balanceAmount200); when(accountManager.getBalance(account)).thenReturn(balanceAmount200); printBalance(balanceAmount200); try { p("Customer.withdraw(" + withdrawlAmount2000 + ") should fail with NotEnoughFundsException"); customer.withdraw(withdrawlAmount2000); } catch (NotEnoughFundsException e) { p("NotEnoughFundsException is thrown"); verify(accountManager).findAccount(customer); p("Verified findAccount(customer) is called"); verify(accountManager, times(0)).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is not called"); throw e; } } @Test public void withdraw() throws NotEnoughFundsException { long balanceAmount3000 = 3000L; p("Train getBalance(account) to return " + balanceAmount3000); when(accountManager.getBalance(account)).thenReturn(balanceAmount3000); printBalance(balanceAmount3000); p("Customer.withdraw(" + withdrawlAmount2000 + ")"); customer.withdraw(withdrawlAmount2000); verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is Called"); verify(accountManager, times(2)).getBalance(account); p("Verified getBalance(account) is called twice"); verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is called just once"); verify(accountManager, atLeastOnce()).findAccount(customer); p("Verified findAccount(account) is called atleast once"); } @Test public void withdrawAndVerifyOrder() throws NotEnoughFundsException { long balanceAmount3000 = 3000L; p("Train getBalance(account) to return " + balanceAmount3000); when(accountManager.getBalance(account)).thenReturn(balanceAmount3000); printBalance(balanceAmount3000); p("Customer.withdraw(" + withdrawlAmount2000 + ")"); customer.withdraw(withdrawlAmount2000); p("Verify order of method calls"); InOrder order = inOrder(accountManager); order.verify(accountManager).findAccount(customer); p("Verified findAccount(account) is called"); order.verify(accountManager).getBalance(account); p("Verified getBalance(account) is called"); order.verify(accountManager).withdraw(account, withdrawlAmount2000); p("Verified withdraw(account, " + withdrawlAmount2000 + ") is called"); order.verify(accountManager).getBalance(account); p("Verified getBalance(account) is called one more time after withdrawl"); verifyNoMoreInteractions(accountManager); p("verified no more calls are executed on the mock object"); } private static void p(String text) { System.out.println(text); } private void printBalance(long balance) { p("Balance is " + balance + " and withdrawl amount " + withdrawlAmount2000); } }
Output:
Train getBalance(account) to return 3000 Balance is 3000 and withdrawl amount 2000 Customer.withdraw(2000) Verify order of method calls Verified findAccount(account) is called Verified getBalance(account) is called Verified withdraw(account, 2000) is called Verified getBalance(account) is called one more time after withdrawl verified no more calls are executed on the mock object PASSED: withdrawAndVerifyOrder
6. Download the Eclipse Project
This was an example of Mockito Verify.
You can download the full source code of this example here: mockitoVerify.zip