How should you unit test the DAO layer

Keywords: Hibernate xml Database JDBC

If you work on projects that use Spring, Hibernate, JPA, and you want to unit test the Data Connection Layer (DAO), this article may help you.

When you plan to test the DAO layer, you need to connect to the database. But you are not allowed to use existing databases. There may be two reasons. One is that you are likely to corrupt the data that will be used to integrate the tests, and the other is that the data is dedicated to other developers.

To solve this problem, in-memory database will be used. Memory databases are a good choice. The reason is that it does not leave any trace after the completion of the test, and can ensure that the database is empty before each test, without any tables.

A good DAO test should ensure that the database is in the same state before and after the test. Roll back all updates without adding new data.

1. Always create the specified configuration file for unit tests

This can be the first step in creating a DAO unit test. This test specifies that the configuration file is mainly used to test the data source information, that is, to connect to the memory database, covering the main configuration file data source. For example, the data source of the main configuration file application-context.xml is MySQL, while the reusable application-context.xml of the test specified configuration file application-context-test.xml is built as a hsqldb main memory database in addition to the data source.

application-context-test.xml

<beans xmlns="http://www.springframework.org/schema/beans" ...>

	<import resource="application-context.xml" />

	<bean id="entityManagerFactoryBean"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />

		<property name="packagesToScan" value="com.lun.entity" />

		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
		</property>
		<property name="jpaProperties">
			<props>
				<prop key="hibernate.archive.autodetection">class,hbm</prop>
				<prop key="hibernate.hbm2ddl.auto">create</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
			</props>
		</property>
	</bean>

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
		<property name="url" value="jdbc:hsqldb:mem:lun" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>

</beans>

application-context.xml

<beans xmlns="http://www.springframework.org/schema/beans" ...>

	<context:component-scan base-package="com.lun" />

	<bean id="entityManagerFactoryBean"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />

		<property name="packagesToScan" value="com.lun.entity" />

		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
		</property>
		<property name="jpaProperties">
			<props>
				<prop key="hibernate.archive.autodetection">class,hbm</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
			</props>
		</property>
	</bean>

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url"
			value="jdbc:mysql://127.0.0.1:3306/learnspring?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC" />
		<property name="username" value="root" />
		<property name="password" value="123" />
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactoryBean" />
	</bean>

	<tx:annotation-driven />

</beans>

2. Writing DAO Layer Unit Tests

The following examples will use Spring-test and Junit test frameworks.

@ContextConfiguration(locations = "classpath:application-context-test.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class TestEmployeeDAO {

	@Autowired
	private EmployeeDAO employeeDAO;

	@Autowired
	private DepartmentDAO departmentDAO;

	@Rollback(true)
	@Transactional
	@Test
	public void testAddDepartment() {
		DepartmentEntity department = new DepartmentEntity("Information Technology");
		departmentDAO.addDepartment(department);

		List<DepartmentEntity> departments = departmentDAO.getAllDepartments();
		Assert.assertEquals(department.getName(), departments.get(0).getName());
	}

	@Test
	@Transactional
	@Rollback(true)
	public void testAddEmployee() {
		DepartmentEntity department = new DepartmentEntity("Human Resource");
		departmentDAO.addDepartment(department);

		EmployeeEntity employee = new EmployeeEntity();
		employee.setFirstName("Lokesh");
		employee.setLastName("Gupta");
		employee.setEmail("howtodoinjava@gmail.com");
		employee.setDepartment(department);

		employeeDAO.addEmployee(employee);

		List<DepartmentEntity> departments = departmentDAO.getAllDepartments();
		List<EmployeeEntity> employees = employeeDAO.getAllEmployees();

		Assert.assertEquals(1, departments.size());
		Assert.assertEquals(1, employees.size());

		Assert.assertEquals(department.getName(), departments.get(0).getName());
		Assert.assertEquals(employee.getEmail(), employees.get(0).getEmail());
	}
}

A few points need to be noted

1. Load the test specified configuration file before starting the test.

@ContextConfiguration(locations = "classpath:application-context-test.xml")

2. Once the configuration file is loaded, dependencies can be easily injected.

@Autowired
private EmployeeDAO employeeDAO;

@Autowired
private DepartmentDAO departmentDAO;

3. Restore the database state with @Rollback(true) annotation.

@Test
@Transactional
@Rollback(true)
public void testAddDepartment()
{
	//other code
}

4. Each test should create some data and validate it. Importantly, each test case is independent and cannot be dependent.

III. Project structure

Source code

Quote

1.How you should unit test DAO layer

Posted by AdamBrill on Fri, 17 May 2019 19:46:11 -0700