Skip to content

Mock Unit Testing Services and Daos with Mockito and Spring 3

If you haven’t been mocking yet, check this out. There are other tools in Groovy using DSLs but if you want to stick to Java, Mockito is by far the best BDD-style mock unit testing tool.

Traditional examples provide a List mocking example or foo/bar example which I find it mostly annoying since it doesn’t teach you how to solve real problems. And the documentation is verbose and crams with unnecessary features confusing us further. In this tutorial, I’ll dive straight into a relevant example of mock testing Daos in Service layer. I’m not a big fan of Daos anymore (after the advent of JPA), however for the purposes of this tutorial, it’ll be easier to explain.

Consider a Profile entity (like facebook user profile) with daos/services: ProfileDao/JPAProfileDao, ProfileService/ProfileServiceImpl. To complicate things further, say you are using DTOs since it’s a client server app with a GWT front end. You might need a simple mapper class. Let’s call it ProfileMapper/ProfileMapperImpl.

@Service("profileService")
public class ProfileServiceImpl implements ProfileService {
	private final ProfileDao profileDao;
	private final ProfileMapper profileMapper;

	@Inject
	public ProfileServiceImpl(final ProfileDao profileDao, final ProfileMapper profileMapper) {
		this.profileDao = profileDao;
		this.profileMapper = profileMapper;
	}

	@Transactional
	public void create(ProfileDto profile) throws DuplicateProfileException {
		if (profile == null) {
			throw new IllegalArgumentException("profile cannot be null.");
		}

		Profile profile = profileMapper.toEntity(profile);
		// set default state as active
		profile .setIsActive(true);
		
		try {
			profileDao.save(profile);
		}
		catch (DuplicateKeyException e) {
			logger.warn("Unable to save profile with userId: " + profile.getUserId() + " already exists.");
			throw new DuplicateProfileException();
		}
		logger.debug("Profile saved successfully.");
	}

	@Transactional(readOnly = true)
	public ProfileDto read(String userId) throws InvalidProfileException {
		validateProfileInfo(userId);

		ProfileDto profileDto = null;
		Profile profile = profileDao.read(userId);
		if (profile != null) {
			profileDto = profileMapper.fromEntity(profile);
			logger.debug("Profile retrieved successfully.");
		}
		else {
			logger.debug("...");
		}
		return profileDto;
	}
	
	...
}

Now, in order to test ProfileService, you need to mock out ProfileMapper and ProfileDao, right? Let’s see how we do this in a simple JUnit 4.4+ test.

import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ProfileServiceTest {

	@Mock
	ProfileDao profileDao;

	@Mock
	ProfileMapper profileMapper;

	// Can't use @InjectMocks because Mockito doesn't support constructor injection
	// As a workaround use @Before below to initialize service with stubs
	ProfileService profileService;

	@Before
	public void init() {
		profileService = new ProfileServiceImpl(profileDao, profileMapper);
	}

	@Test
	public void testRead() throws InvalidProfileException {
		// Simulate InvalidProfileException
		try {
			profileService.read("");
			fail(); // should never execute
		}
		catch (InvalidProfileException e) {
			e.getMessage(); // expected
		}

		// Given
		Profile profile = TestData.createTestProfile("userid"); // test utility to create a test Profile
		when(profileDao.read("userid")).thenReturn(profile);
		when(profileMapper.fromEntity(profile )).thenReturn(TestData.createTestProfileDto("userid"));

		// When
		ProfileDto dto = profileService.read("userid");

		// Then
		assertEquals(dto.getUserId(), "userid");
	}
}

Explanation:
1) Wrapping your test with @RunWith(MockitoJUnitRunner.class) helps create the mock initialization through annotation scanning (@Mock, @InjectMocks)
2) Add @Mock annotations for the components to mock. In this case profileDao, profileMapper
3) As of 1.8.5, Mockito doesn’t provide @InjectMock with construction injection. @Before test initializer is a workaround to inject ProfileService with mocks. Note that this will not be required if ProfileService has setter/getter injection of dependencies. However, I prefer JSR330 construction injection which is a best practice .
4) The actual @Test class with mockito stubs. Let’s dig deep into this.

As a template, it’s a good practice to view tests like a BDD style test.

// Given 

// When


// Then 

The above template forces you to think on the explicit conditions during which we run our unit test.

Next, we need to figure out a way to stub our mock component’s methods,

when(operation).thenReturn(object) 

In our example we want to mock profileDao.read(userId). So that translates to

when(profileDao.read("userid")).thenReturn(profile);		

Note that we’re letting the mocked dao return a profile object that we just created in the previous step. This will be 50% of most of your mocking use cases.

The next common used use case is to simulate exceptions from the mocked classes. Consider a test for create(…) that simulates the DuplicateProfileException.

@Test
	public void testCreateDuplicate() {
		// Given
		ProfileDto dto = TestData.createTestProfileDto("userid");
		Profile profile = TestData.createTestProfile("userid");
		when(profileMapper.toEntity(dto)).thenReturn(profile);
		doThrow(new DuplicateKeyException("duplicate profile")).when(profileDao).save(profile);

		// When
		try {
			profileService.create(dto);
			assertEquals(1, 2); // should never execute
		}
		// Then
		catch (DuplicateProfileException e) {
			e.getMessage();
		}
	}

Notice the line

doThrow(new DuplicateKeyException("duplicate profile")).when(profileDao).save(profile);

Quite simple, isn’t it?

If you’ve read so far, you can succuessfully write mock unit tests for 80% of your use cases. There are other advanced features like finding redundant invocations, spying on objects to simulate partial mocking, most of which I don’t see implementing for majority of my use cases.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

7 Comments

  1. Joris wrote:

    Nice read & learned something new from it!

    Although I don’t get why you would write something like

    assertEquals(1, 2); // should never execute

    You could change it to make it a bit more understandable
    http://junit.sourceforge.net/javadoc/org/junit/Assert.html#fail(java.lang.String)

    Wednesday, May 18, 2011 at 6:10 pm | Permalink
  2. Priyatam wrote:

    Good point. I was too lazy too read the api.

    Wednesday, May 18, 2011 at 8:17 pm | Permalink
  3. Davy wrote:

    Thank you for your example of using mockito.

    I would split the “testRead” method in several methods testing only one behaviour, for example “testEmptyReadThrowsInvalidProfileException” and “testValidReadReturnsCorrectDto”

    I would also test that an exception is thrown using @Test(expected=YourException.class): see http://junit.sourceforge.net/javadoc/org/junit/Test.html#expected() and http://junit.sourceforge.net/doc/cookbook/cookbook.htm (at the end of the page) for an example.

    Thursday, June 16, 2011 at 2:18 pm | Permalink
  4. Taran Singh wrote:

    Gr8 article and I def. I agree the annoying foo/bar doesn’t give anything solid especially when you run into errors :(

    TestData.createTestProfile(“userid”); Here still we are incurring some manual labour to create a class and method to return us a profile and to me it looks like not mocking completely, but may be in future what I would like to have is that you just specify the data somehow and get the object created. Thanks

    Thursday, November 3, 2011 at 12:24 pm | Permalink
  5. Ajinkya wrote:

    Best and easy example so far :)
    Keep the good work up!

    Friday, December 23, 2011 at 7:28 am | Permalink
  6. David Hilton wrote:

    A great example.

    I agree with your comments about other examples using lists since they didn’t reflect Martin Fowler’s discussion about the ‘subject under test’ as distinct the collaborator (http://martinfowler.com/articles/mocksArentStubs.html), in list examples I think they have collapsed the ‘subject under test’ and collaborator together as one in order to showcase mockito easier but this cause confusion about the right technique when mocking.

    I am not sure where Spring is coming in here, that’s why I was looking at your article in the first place(google, “Spring and Mockito”), your example is a straight Mockito test i.e. there is no Spring dependency injection (maybe I have the wrong end of the stick?)

    None the less, a good Mockito example.

    Wednesday, January 18, 2012 at 3:47 pm | Permalink
  7. Priyatam wrote:

    @DAVID – Spring comes into play via the @Service annotations and/or @Inject/@Transactional. Not sure what in Spring you would want to mock; the approach, though, is similar.

    Wednesday, January 18, 2012 at 11:32 pm | Permalink

2 Trackbacks/Pingbacks

  1. [...] REVERT TO CONSOLE › Mock Unit Testing Services and Daos with Mockito and Spring 3 – Mock Unit Testing Services and Daos with Mockito and Spring 3 [...]

  2. [...] Mock Unit Testing Services and Daos with Mockito and Spring 3 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*