Статьи

JUnit Testing Spring Service и DAO (с базой данных в памяти)

В этом посте описывается, как реализовать тесты JUnit для сервисов и DAO веб-приложения Spring. Он построен поверх примера архитектуры Spring MVC-Service-DAO-Persistence . Этот пример доступен на Github в каталоге Spring-Web-JPA-Testing.

напоминание

  • Test Fixture — фиксированное состояние, используемое в качестве основы для выполнения тестов.
  • Модульный тест — эти тесты проверяют, что части кода (компоненты) выполняют некоторые функции, как ожидалось. В среде Java они обычно реализуются на уровне класса.
  • Интеграционный тестИнтеграционный тест — это любой тип теста, который проверяет, что набор взаимодействующих компонентов правильно выполняет ожидаемые функции.

конфигурация

Нам нужна конфигурация JPA Hibernate для тестирования в памяти:

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
50
51
52
53
54
55
56
57
58
59
60
@Configuration
@EnableTransactionManagement
public class JpaTestConfig {
 
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
 
        LocalContainerEntityManagerFactoryBean lcemfb
            = new LocalContainerEntityManagerFactoryBean();
 
        lcemfb.setDataSource(this.dataSource());
        lcemfb.setPackagesToScan(new String[] {'com.jverstry'});
        lcemfb.setPersistenceUnitName('MyTestPU');
 
        HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
        lcemfb.setJpaVendorAdapter(va);
 
        Properties ps = new Properties();
        ps.put('hibernate.dialect', 'org.hibernate.dialect.HSQLDialect');
        ps.put('hibernate.hbm2ddl.auto', 'create');
        lcemfb.setJpaProperties(ps);
 
        lcemfb.afterPropertiesSet();
 
        return lcemfb;
 
    }
 
    @Bean
    public DataSource dataSource(){
 
        DriverManagerDataSource ds = new DriverManagerDataSource();
 
        ds.setDriverClassName('org.hsqldb.jdbcDriver');
        ds.setUrl('jdbc:hsqldb:mem:testdb');
        ds.setUsername('sa');
        ds.setPassword('');
 
        return ds;
 
    }
 
    @Bean
    public PlatformTransactionManager transactionManager(){
 
        JpaTransactionManager tm = new JpaTransactionManager();
 
        tm.setEntityManagerFactory(
            this.entityManagerFactoryBean().getObject() );
 
        return tm;
 
    }
 
    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }
 
}

Нам нужно исключить рабочую конфигурацию из сканирования пакетов (без сканирования com.jverstry):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Configuration
@ComponentScan(basePackages = {
    'com.jverstry.Controller',
    'com.jverstry.DAO',
    'com.jverstry.Item',
    'com.jverstry.Service'
})
 
public class TestConfig {
 
    @Bean
    public MyService getMyService() {
        return new MyServiceImpl();
    }
 
}


Инструменты весеннего тестирования

  • @RunWith — это аннотация JUnit, позволяющая запустить тест с другим бегуном, чем тот, который предоставляется JUnit.
  • SpringJUnit4ClassRunner — это бегущий тест JUnit для приложений Spring. Как правило, тестовые классы обозначаются с помощью @RunWith (SpringJUnit4ClassRunner.class).
  • @ContextConfiguration — эта аннотация может использоваться, чтобы указать, как загрузить applicationContext в тестовом классе Spring. Это можно настроить с помощью файлов XML или объектов конфигурации Java.

Сервисное тестирование

Следующий класс тестирует метод createAndRetrieve () нашей внедренной реализации MyService:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ JpaTestConfig.class, TestConfig.class })
public class MyServiceImplTest {
 
    @Autowired
    private MyService myService;
 
    @Test
    public void testCreateAndRetrieve() {
 
        MilliTimeItem retr = myService.createAndRetrieve();
 
        assertNotNull(retr);
 
    }
 
}


DAO Testing

Следующий класс тестирует нашу реализацию DAO. Наша реализация внедряется с EntityManager, созданным из нашего тестового класса конфигурации, определенного выше.

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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ JpaTestConfig.class, TestConfig.class })
public class MyPersistenceDAOTest {
 
    @Autowired
    private MyPersistenceDAO myDAO;
 
    @Test
    public void testCreateMilliTimeItem() {
 
        // This operation should not throw an Exception
        long id = myDAO.createMilliTimeItem();
 
    }
 
    @Test
    public void testGetMilliTimeItem() {
 
        long id = myDAO.createMilliTimeItem();
        MilliTimeItem retr = myDAO.getMilliTimeItem(id);
 
        assertNotNull(retr);
        assertEquals(id,retr.getID());
 
    }
 
}


Предостережение

Начиная писать тесты JUnit для Spring, можно встретить следующие сообщения об ошибках:

1
2
Java.lang.ClassFormatError:
Absent Code attribute in method that is not native or abstract in class file javax/validation/Validation

Вышесказанное часто вызвано следующей зависимостью maven:

1
2
3
4
5
6
<dependency>
   <groupId>javax</groupId>
   <artifactId>javaee-api</artifactId>
   <version>6.0</version>
   <type>jar</type>
</dependency>

Следует заменить на:

1
2
3
4
5
6
<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-jpa_2.0_spec</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>

Другое сообщение об ошибке:

1
javax.validation.ValidationException: Unable to find a default provider

Это решается добавлением следующей зависимости maven:

1
2
3
4
5
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.3.0.Final</version>
</dependency>

Больше Spring связанных постов здесь .

Ссылка: JUnit Testing Spring Service и DAO (с базой данных в памяти) от нашего партнера JCG Джерома Версринга в блоге технических заметок .