Функциональный тест весной: изменения в базе данных не видны в тесте - PullRequest
0 голосов
/ 11 июня 2011

У меня есть интеграционный тест (который работает под Jetty), где я открываю страницу (с помощью Selenium) и проверяю, что запись об этой деятельности была добавлена ​​в базу данных (HSQL).Но это не работает - JPA (Hiberante) добавляет запись (я вижу это в журналах), но когда я выполняю запрос SELECT, там вообще нет записей.

Контрольный пример:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:spring/DispatcherServletContext.xml"
})
@TransactionConfiguration(defaultRollback = false)
public class WhenUserOpenNotExistingPage
    extends WhenUserAtAnyPage<NotFoundErrorPage> {

    private final String currentUrl;

    @Autowired
    private SuspiciousActivityDao suspiciousActivities;

    private String generateRandomUrl() {
        return String.format(
            "/tests/page-does-not-exists-%s.htm",
            RandomStringUtils.randomNumeric(5)
        );
    }

    public WhenUserOpenNotExistingPage() {
        currentUrl = generateRandomUrl();
        page.open(currentUrl);
    }

    @Test
    @Transactional(readOnly = true)
    public void incidentShouldBeLoggedToDatabase() {
        SuspiciousActivity activity =
            suspiciousActivities.findByPage(currentUrl);

        assertNotNull(activity);
    }
}

Также WhenUserOpenNotExistingPage() (constructorr) вызывается дважды (и я не знаю, почему это происходит, и, вероятно, это корень моей проблемы).

Вы можете мне помочь?Заранее спасибо!

1 Ответ

1 голос
/ 11 июня 2011

Я предполагаю, что вы добавляете что-то в базу данных в тестовом примере, и эта же база данных используется вашим приложением, работающим на Jetty. Если в вашей базе данных используется какой-либо уровень изоляции выше прочитанного незафиксированным, изменения, внесенные в тестовом примере, не будут видны, пока этот тестовый сценарий не завершится. Это связано с тем, что код вашей базы данных присоединяется к транзакции, которая была создана при запуске теста.

По умолчанию эта тестовая транзакция откатывается после завершения теста, поэтому изменения видны в текущем тесте (транзакции), но не видны снаружи (другими потоками / соединениями) и откатываются. Вы изменяете поведение по умолчанию, используя атрибут defaultRollback = false, но это только означает, что изменения, сделанные вами в одном тесте, не видны веб-приложением (другое подключение к базе данных), но будут видны в последующем тесте (после фиксации). Не очень полезно.

У вас есть несколько вариантов:

  • Избавьтесь от поддержки транзакционного тестирования Spring. Это означает, что Spring не будет создавать новую транзакцию при каждом запуске теста и не будет выполнять коммит / откат. Теперь вам решать, когда начинать транзакцию и фиксировать ее перед фактическим запуском теста SElenium.

Это легко сделать, заменив @TransactionConfiguration на:

@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})

это переопределит прослушиватели выполнения теста по умолчанию, удалив TransactionalTestExecutionListener из стека

  • Вы можете запустить установочный код из другого потока или с распространением REQUIRES_NEW

  • Наконец, вы должны рассмотреть возможность установки вне JUnit. Может быть, вы можете сделать настройку из самого приложения?

Что касается конструктора - для каждого теста создается новый экземпляр класса теста JUnit. Авторы JUnit утверждают, что он делает тест более предсказуемым и не сохраняющим состояния (нет зависимости между тестами) за счет очистки класса теста перед запуском каждого теста. На практике, особенно с интеграционными тестами, это больше боль, чем преимущество.

Кстати, если вы выполняете некоторые манипуляции с базой данных в тесте и фиксируете изменения, следите за тестовыми зависимостями. Порядок выполнения тестов не гарантируется в JUnit. Это означает, что изменения в одном тесте не должны влиять на другие тесты.

...