Spring + Mockito test injection Spring + Mockito test injection spring spring

Spring + Mockito test injection


You don't want to test your interface: it contains no code at all. You want to test your implementation. So the setter is available. Just use it:

@Testpublic void testLogin() {    MobileServiceImpl toTest = new MobileServiceImpl();    toTest.setMobileDao(mockMobileDao);    // TODO call the login method and check that it works as expected.}

No need for a spring context. Just instanciate your POJO service, inject mock dependencies manually, and test the methods you want to test.


After struggling with the Springockito XSD issue, for a while, I found a much simpler solution. Let Spring inject the mock for you using a factory method, i.e. in applicationContext.xml put:

<?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>

where the AccountsDAO bean is injected into the BankingService class. The corresponding JUnit test case is:

@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);  }}

Personally I find this very elegant and easy to understand. For more details, see the original blog post.


You have three options to set your mock dao:

  1. Test the implementation - which gives a seam for your mock via the setDao method. (as JB's answer)
  2. Add the setDao method to the interface - not desired since you don't want to add code just to support your tests.
  3. Add a constructor to the impl class to accept the dao - not desired for same reason as #2.

If you wanted to do #3, you'll need to add a constructor to the MobileService that accepts the MobileDao.

   public MobileServiceImpl(MobileDao mobileDao) {    this.mobileDao = mobileDao;}

Then your test will look like this:

import static org.mockito.Mockito.verify;import static org.mockito.Mockito.*;import java.util.Date;import org.junit.Before;import org.junit.Test;public class MobileServiceImplTest {    private MobileService systemUnderTest;    private MobileDao mobileDao;    @Before    public void setup() {        mobileDao = mock(MobileDao.class);        systemUnderTest = new MobileServiceImpl(mobileDao);    }    @Test    public void testGetUser() {        //if you need to, configure mock behavior here.         //i.e. when(mobileDao.someMethod(someObject)).thenReturn(someResponse);        systemUnderTest.getUser("accessCode", new Date());        verify(mobileDao).getUser("JeffAtwood");    }}

Please note that you have not provided us with the details of the MobileDao so I created a getUser method that accepts a String.

To make the test pass, your MobileServiceImpl would just need this:

mobileDao.getUser("JeffAtwood");