In this tutorial you are going to learn how to create unit tests for DAOs. As a prerequisite, you fundamental knowledge of DAOs is expected.
When it comes to testing DAO components, we really have 2 approaches. One is to use the mocking framework Mockito and the other is to create a couple of classes that work together.
In this tutorial, we will be using Mockito.
EmployeeDAO
public class EmployeeDAO implements Dao<Employee> { // will act as a "mini-database" private List<Employee> employees = new ArrayList<>(); private SessionFactory sessFactory; // Constructor public EmployeeDAO(SessionFactory s) { // Populate our list of employees with 3 Demos employees.add(new Employee("Demo1", "Demo1@example.com")); employees.add(new Employee("Demo2", "Demo2@example.com")); employees.add(new Employee("Demo3", "Demo3@example.com")); sessFactory = s; } // Overriding the Dao interface methods @Override public Employee get(long id) { return employees.get((int) id)); } @Override public List<Employee> getAll() { return employees; } @Override public void save(Employee emp) { employees.add(emp); } @Override public void update(Employee employee, String[] params) { // Check for validity if (params[0].length() != 0|| params[1].length() != 0) { // Initialize the employee employee.setName(params[0]); employee.setEmail(params[1]); // Add the Initialized employee to the list of employees (a.k.a. DB) employees.add(employee); } } @Override public void delete(Employee employee) { employees.remove(employee); } }
If you are wondering how the Employee class looks like, here it is:
Employee.java
public class Employee { //members private String name; private String email; // constructor Employee(String n, String e) { name = n; email = e; } // setter methods public void setName(String n) { name = n; } public void setEmail(String e) { email = e; } // getter methods public String getName() { return name; } public String getEmail() { return email; } }
The employee class is just a standard constructor/getter/setter methods.
Now it is time to create the test class for the DAO class.
EmployeeDAOTest
@ExtendWith(SpringExtension.class) @Tag("DAO") public class EmployeeDAOTest { @MockBean private SessionFactory sessionFactory; @MockBean private Session session; private EmployeeDAO employeeDAO; @BeforeEach public void prepare() throws Exception { Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session); employeeDAO = new EmployeeDAO(sessionFactory); } @Test public void should_returnNull_ifNonExistent() { Query q = Mockito.mock(Query.class); Mockito.when(session.getNamedQuery("get")).thenReturn(q); Mockito.when(q.getResultList()).thenReturn(new ArrayList()); List l = employeeDAO.getAll(); assertAll("Employees", () -> assertNotEquals(l, null), () -> assertEquals(l.size(), 0)); } }
Breakdown
There are a couple of things to break down in the preceding class.
First, note that we are using the @MockBean annotation which simply put adds mock objects to the application context. Meaning, this will replace any existing bean of the same type. In case there haven’t been any existing beans, a new one will be created.
Then we use the @BeforeEach annotation which will get executed before all the unit tests run. Hence the name of the method, prepare, we are preparing the “environment” for the unit tests.
Within the prepare method, we have a couple of things. Since SessionFactory is a functional interface, it can be used as the assignment for a lambda expression.
We use the Mockito.when method in the prepare() method. It is used for mocking methods which given an exception during a call. So the line
Mockito.when(sessionFactory.getCurrentSession()).thenReturn(session);
really is saying “get me the current session and if there are no exception, return me the session”. And after that, we simply assign the DAO instance to a brand new one:
employeeDAO = new EmployeeDAO(sessionFactory);
After that, we have our very test purpose method, called should_returnNull_ifNonExistent() and does just what the name of it says: returns a null, or an empty ArrayList if there isn’t a list to return. In our EmployeeDAO implementation though, we will never run the risk of getting null as we add three Employee entries in the List as soon as we create an instance of EmployeeDAO():
public EmployeeDAO(SessionFactory s) { // Populate our list of employees with 3 Demos employees.add(new Employee("Demo1", "Demo1@example.com")); employees.add(new Employee("Demo2", "Demo2@example.com")); employees.add(new Employee("Demo3", "Demo3@example.com")); sessFactory = s; }
Note the @Test annotation of the method. This specifies that this method is for testing purposes. We get the “get” method overriden by us in the EmployeeDAO class and if there are not exceptions, thenReturn the q which is of type Query. Then we get simply return a new empty array list.
After that, we use the getAll() method that should give us back 3 entries at least and then we use the assertAll() method which combines assertNotEquals and assertEquals. The lines:
assertAll("Employees", () -> assertNotEquals(l, null), () -> assertEquals(l.size(), 0));
are really saying check whether l (the list that contains the entries that have been returned from the getAll() method) is not empty and check if the size of the list is 0. If it is, return true, assertEquals would evaluate to true.