Статьи

Насколько круто интеграционное тестирование с Spring и Hibernate

Я виновен в том, что до сих пор не писал интеграционное тестирование (по крайней мере, для транзакций, связанных с базой данных). Поэтому, чтобы искоренить вину, я прочитал о том, как можно достичь этого с минимальными усилиями в выходные дни. Придумал небольшой пример, показывающий, как этого легко добиться, используя Spring и Hibernate. С помощью интеграционного тестирования вы можете протестировать свой уровень DAO (объекта доступа к данным) без необходимости развертывания приложения. Для меня это огромный плюс, так как теперь я могу даже тестировать свои критерии, именованные запросы и сортировку без необходимости запускать приложение.

В hibernate есть свойство, позволяющее указать сценарий sql, запускаемый при инициализации фабрики сеансов. Теперь я могу заполнять таблицы данными, которые требуются для моего уровня DAO. Свойство выглядит следующим образом;

1
<prop key='hibernate.hbm2ddl.import_files'>import.sql</prop>

Согласно документации по hibernate, у вас может быть много SQL-скриптов, разделенных запятыми. Один из моментов здесь заключается в том, что вы не можете создавать таблицы, используя скрипт. Потому что для запуска скрипта сначала необходимо создать схему. Даже если вы выполняете оператор create table внутри скрипта, он игнорируется при выполнении скрипта, как я его видел.

Позвольте мне сначала показать вам класс DAO, который я собираюсь проверить;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.unittest.session.example1.dao;
 
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
 
import com.unittest.session.example1.domain.Employee;
 
@Transactional(propagation = Propagation.REQUIRED)
public interface EmployeeDAO {
 
 public Long createEmployee(Employee emp);
 
 public Employee getEmployeeById(Long id);
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.unittest.session.example1.dao.hibernate;
 
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
 
import com.unittest.session.example1.dao.EmployeeDAO;
import com.unittest.session.example1.domain.Employee;
 
public class EmployeeHibernateDAOImpl extends HibernateDaoSupport implements
  EmployeeDAO {
 
 @Override
 public Long createEmployee(Employee emp) {
  getHibernateTemplate().persist(emp);
  return emp.getEmpId();
 }
 
 public Employee getEmployeeById(Long id) {
  return getHibernateTemplate().get(Employee.class, id);
 }
}

Ничего особенного, просто простой DAO с двумя методами, один из которых должен быть сохранен, а другой — получить. Для проверки метода поиска мне нужно заполнить таблицу Employee некоторыми данными. Именно здесь вступает в игру сценарий импорта sql, который был описан ранее. Файл import.sql выглядит следующим образом;

1
insert into Employee (empId,emp_name) values (1,'Emp test');

Это просто основной скрипт, в котором я вставляю одну запись в таблицу сотрудников. Здесь еще раз обратите внимание, что для запуска сценария sql таблицу сотрудника следует создать с помощью параметра DDL автоматического создания hibernate. Более подробную информацию можно найти здесь . Также сценарий import.sql в моем случае находится в classpath. Это необходимо для того, чтобы его можно было выполнить при создании фабрики сеансов.

Далее давайте посмотрим, насколько легко запустить интеграционные тесты с помощью Spring.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.unittest.session.example1.dao.hibernate;
 
import static org.junit.Assert.*;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
 
import com.unittest.session.example1.dao.EmployeeDAO;
import com.unittest.session.example1.domain.Employee;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations='classpath:spring-context.xml')
@TransactionConfiguration(defaultRollback=true,transactionManager='transactionManager')
public class EmployeeHibernateDAOImplTest {
 
 @Autowired
 private EmployeeDAO employeeDAO;
 
 @Test
 public void testGetEmployeeById() {
  Employee emp = employeeDAO.getEmployeeById(1L);
 
  assertNotNull(emp);
 }
 
 @Test
 public void testCreateEmployee()
 {
  Employee emp = new Employee();
  emp.setName('Emp123');
  Long key = employeeDAO.createEmployee(emp);
 
  assertEquals(2L, key.longValue());
 }
 
}

Несколько вещей, на которые следует обратить внимание, это то, что вам нужно дать команду запустить тест в контексте Spring. Для этого мы используем SpringJUnit4ClassRunner . Также атрибут transction установлен в defaultRollback = true. Обратите внимание, что для работы MySQL в ваших таблицах должен быть установлен механизм InnoDB, так как механизм MyISAM не поддерживает транзакции.

И наконец я представляю конфигурацию пружины, которая соединяет все;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version='1.0' encoding='UTF-8'?>
 xsi:schemaLocation=' 
 
 <context:component-scan base-package='com.unittest.session.example1' />
 <context:annotation-config />
 
 <tx:annotation-driven />
 
 <bean id='sessionFactory'
  class='org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean'>
  <property name='packagesToScan'>
   <list>
    <value>com.unittest.session.example1.**.*</value>
   </list>
  </property>
  <property name='hibernateProperties'>
   <props>
    <prop key='hibernate.dialect'>org.hibernate.dialect.MySQLDialect</prop>
    <prop key='hibernate.connection.driver_class'>com.mysql.jdbc.Driver</prop>
    <prop key='hibernate.connection.url'>jdbc:mysql://localhost:3306/hbmex1</prop>
    <prop key='hibernate.connection.username'>root</prop>
    <prop key='hibernate.connection.password'>password</prop>
    <prop key='hibernate.show_sql'>true</prop>
    <prop key='hibernate.dialect'>org.hibernate.dialect.MySQLDialect</prop>
    <!-- -->
    <prop key='hibernate.hbm2ddl.auto'>create</prop>
    <prop key='hibernate.hbm2ddl.import_files'>import.sql</prop>
   </props>
  </property>
 </bean>
 
 <bean id='empDAO'
  class='com.unittest.session.example1.dao.hibernate.EmployeeHibernateDAOImpl'>
  <property name='sessionFactory' ref='sessionFactory' />
 </bean>
 
 <bean id='transactionManager'
  class='org.springframework.orm.hibernate3.HibernateTransactionManager'>
  <property name='sessionFactory' ref='sessionFactory' />
 </bean>
 
</beans>

Это об этом. Лично я бы предпочел использовать более легковесную базу данных в памяти, такую ​​как hsqldb , чтобы запустить свои интеграционные тесты.

Вот проект eclipse для тех, кто хотел бы запустить программу и попробовать ее.

Справка: насколько круто интеграционное тестирование с Spring + Hibernate от нашего партнера по JCG Динуки Арурилератне в блоге My Journey By IT .