DAO unit testing with junit and mockito

If it’s not tested, it’s broken. – Bruce Eckel

I’m a great fan of reliable software. And working in the software development industry I only want to create software that works as reliable as possible. In my opinion crashes in any software (or even worse: data loss) cause such a huge distrust from the user, it is likely to prevent him from using a software ever again. Ask yourself the question: Would you want to run a piece of software that crashes? I wouldn’t. That’s why I think that quality assurance and especially testing your software (and finding crashes before your user does) is the most important part of software development.

So how do we test software? As usual Wikipedia can tell you all about the different types of testing. As well as many blogs, tutorials and similar all around the internet. You can easily see: there is a large amount of ways to ensure the quality of your software. I’ll focus on a type of testing typically done by software developers: unit testing. Unit testing is done, as the name suggests, one a „unit“ of the software. What a unit is can vary based on usecases, types of software and even programming languages. In this example we will use Java classes and their methods as a unit. So let’s start with a trivial example unit, the SomeDao:

package de.egore911.test;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Id;

public class SomeDao {
    public static class Some {
        @Id public Integer id;
    }

    @Inject private EntityManager em;

    protected EntityManager getEntityManager() { return em; }

    public Some comeGetSome(Integer id) {
        return getEntityManager().find(Some.class, id);
    }
}

We have a DAO (data access object) which is able to load entities of the type Some by their ID. The class itself uses CDI to inject the EntityManager instance. This is a very common type of class I’ve seen in lots of web projects, but how to test this unit? At first glance it depends on an injection framework, which needs an entity-manager, which needs a database, which needs dummy data. Any of these dependencies could cause the test to fail that should therefore not be part of this unit test (e.g. the database was not available). A unit should be self contained, external dependencies must be mocked. A mock is essentially a black box, which has a guaranteed output for a given input. So we need to have a mock object for the EntityManager, which does not actually need to be injected and also does not need a database. This is where Mockito comes into play to create this mock.

import javax.persistence.EntityManager;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class SomeDaoTest {

    @Test
    public void testComeGetSome() {
        // Given: A mock the EntityManager to return our dummy element
        Some dummy = new Some();
        EntityManager em = Mockito.mock(EntityManager.class);
        Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);

        // Also given: Our mocked SomeDao using our EntityManager and
        // allowing only the call to comeGetSome
        SomeDao someDao = Mockito.mock(SomeDao.class);
        Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod();
        Mockito.when(someDao.getEntityManager()).thenReturn(em);

        // Perform the actual test
        Assertions.assertSame(dummy, someDao.comeGetSome(1234));
        Assertions.assertNull(someDao.comeGetSome(4321));
    }
}

The example above kept simple and therefore the actual test code would not make much sense, as we only test our mock (as the actual DAO does not have any logic). Once the DAO has actual logic (e.g. parameter parsing or using the criteria API) it gets more interesting. First you mock an EntityManager that will return a dummy object when the EntityManager.find() method called. Then we make sure our mocked EntityManager is returned when SomeDao.getEntityManager() is called and also the real SomeDao.comeGetSome() is invoked. Of course all this could be done using reflection ourselves, but mockito does all the hard work for us.

To simplify this even further, you can also use Mockito features to inject mocks for you. The example below shows an equivalent implementation using the InjectMocks annotation.

import javax.persistence.EntityManager;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class SomeDaoTest {

    @Mock
    private EntityManager em;

    @InjectMocks
    SomeDao someDao;

    @Test
    public void testComeGetSome() {
        // Given: Tell the mocked entitymanager to return our dummy element
        Some dummy = new Some();
        Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);
        Mockito.when(em.find(Some.class, Mockito.any(Integer.class))).thenReturn(null);

        // Perform the actual test
        Assertions.assertSame(dummy, someDao.comeGetSome(1234));
        Assertions.assertNull(someDao.comeGetSome(4321));
    }
}
Copyright © christophbrill.de, 2002-2020.