Unit Testing Spring Bean Service With Mockito

The main idea of unit testing is quick compile-time checking that your code (somewhat) fulfills the business requirement.

A good unit testing practice is to not depend on any external system / dependencies. One way to substitute this external dependency is by using mocking tehcniques. Here I’ll go through unit testing a Spring bean service using Mockito.

Assuming you have a BankingService class that comes with a method to transfer money from one account to another. The method finds the Account object by its id using AccountsDAO repository class:

@Service
public class BankingService {

  @Autowired private AccountsDAO accountsDAO;
  
  public void transfer(long fromAccountId, long toAccountId, double amount) throws Exception {
    Account fromAccount = accountsDAO.findById(fromAccountId);
    Account toAccount = accountsDAO.findById(toAccountId);
    
    fromAccount.setBalance(fromAccount.getBalance() - amount);
    toAccount.setBalance(toAccount.getBalance() + amount);
  }
}

AccountsDAO obtain the information from a persistent data store (most likely database), hence it is an external dependency. Here’s how to unit test this class:

  1. Ensure junit, spring-test and mockito dependencies are on the classpath
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>3.2.3.RELEASE</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>1.9.5</version>
      <scope>test</scope>
    </dependency>
    
  2. Setup BankingServiceTest.xml spring beans configuration file specific for our unit test. Note in here we created a mock AccountsDAO using Mockito. The order of mock creation here is important, if you place it at the bottom you will get autowiring error. I think this is because Spring couldn’t pre-determine the resulting type of the Mock object (it only looks as if it’s a org.mockito.Mockito bean type).
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean class="org.mockito.Mockito" factory-method="mock">
        <constructor-arg value="com.gerrydevstory.mycoolbank.AccountsDAO"/>
      </bean>
    
      <bean class="com.gerrydevstory.mycoolbank.BankingService"/>
    
    </beans>
    
  3. Setup the unit test class. Notice the BankingService to test and the mock AccountsDAO are autowired into the unit test class
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("/BankingServiceTest.xml")
    public class BankingServiceTest {
    
      @Autowired private BankingService bankingService;
      @Autowired private AccountsDAO mockAccountsDAO;
      
      @Test
      public void testTransfer() throws Exception {
        // Setup 2 accounts
        Account acc1 = new Account();
        acc1.setBalance(800.00);
        Account acc2 = new Account();
        acc2.setBalance(200.00);
        
        // Tell mock DAO to return above accounts when 1011 or 2041 is queried respectively
        when(mockAccountsDAO.findById(1011)).thenReturn(acc1);
        when(mockAccountsDAO.findById(2041)).thenReturn(acc2);
        
        // Invoke the method to test
        bankingService.transfer(1011, 2041, 500.00);
        
        // Verify the money has been transferred
        assertEquals(300.00, acc1.getBalance(), 0.001);
        assertEquals(700.00, acc2.getBalance(), 0.001);
      }
    }
    
  4. The when(..).thenReturn(..) syntax is where the magic happen. It will cause the mock object to return the Account we setup (as opposed of calling SQL to fetch it from database).

There are heaps more magic stuff you can do with Mockito. Checkout their site.

Source Code

Source code of this demo can be downloaded via git:

git clone https://gerrytan@bitbucket.org/gerrytan/mycoolbank.git

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s