воскресенье, 30 ноября 2008 г.

Тестирование при помощи JUnit и Spring-Tests

При разработке веб-приложений с помощью связки Spring+Hibernate тестирование становится достаточно нетривиальной задачей, если подходить к ней в лоб. В процессе запуска теста необходимо выполнить следующие шаги: поднять контекст Spring'a, произвести необходимые dependency-injection, обеспечить открытую сессию Hibernate на протяжении выполнения теста (в веб-приложениях эту работу выполняет OpenSessionInViewFilter, который держит сессию открытой на период обслуживания запроса пользователя). Рассмотрим как это сделать на примере использования распространенного фреймворка для тестирования JUnit версии 4.4 (более новая версия 4.5 имеет проблемы совместимости со Spring) и модуля Spring-tests из SpringModules (spring-test.jar). Класс простейшего теста приведен ниже:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-config.xml" })
public class MessageServiceTest {

private MessageStringDataServiceInterface messageStringDataService;
private DefaultWebConfig defaultWebConfig;
private SessionFactory sessionFactory;

@Autowired
public void setDefaultWebConfig(DefaultWebConfig defaultWebConfig) {
this.defaultWebConfig = defaultWebConfig;
}

@Autowired
public void setMessageStringDataService(
MessageStringDataServiceInterface messageStringDataService) {
this.messageStringDataService = messageStringDataService;
}

@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Test
public void onSetUp() {
TransactionSynchronizationManager.bindResource(sessionFactory,
new SessionHolder(sessionFactory.openSession()));
}

@Test
public void testMessageDataService() throws DomainException {
assertNull(messageStringDataService.getMessageString("test.message",
defaultWebConfig.getDefaultLanguage()));
}

@Test
public void onTearDown() {
TransactionSynchronizationManager
.unbindResourceIfPossible(sessionFactory);
}
}
Для того, чтобы при запуске теста поднимался контекст Spring'a необходимо аннотировать класс при помощи следующих аннотаций:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-config.xml" })
Первая из них сообщает Spring'у, что надо использовать специальный wrapper для запуска этого теста в JUnit, а вторая указывает имя конфигурационного файла контекста. Все конфигурационные файлы, на которые есть ссылки в конфиге контекста должны находиться также в classpath для корректного запуска теста. После этого можно устанавливать все зависимости при помощи аннотации @Autowired. Аннотация @Test относится к JUnit и ей маркируются собственно методы для тестирования. Выполняются они в порядке следования в коде, поэтому методы onSetUp() и onTearDown() будут выполнены соответственно в первую и в последнюю очередь. Это мы и используем для демаркации сессии при помощи менеджера транзакций Spring. Примерно так же работает и OpenSessionInViewFilter, который при старте обработки запроса пользователя открывает сессию и затем привязывает ее к сессии, а при окончании обработки запроса - освобождает ресурс. Два вышеописанных метода выполняют аналогичную функцию. На этом интеграционную часть можно считать раскрытой, а по новым возможностям JUnit рекомендую краткий обзор с примерами.

Комментариев нет: