Как сбросить @Repository после каждого теста в SpringBootTest?

Я пытаюсь собрать интеграционный тест для моего недавно созданного класса @Repository, однако мне не повезло с запуском всех тестов вместе. Если я запускаю каждый тест отдельно - они проходят, однако, если я запускаю весь тестовый класс - два теста терпят неудачу, пытаясь найти одну строку по идентификатору в H2 (отдельный db для тестирования) и не найти ни одного.

Это мой тестовый класс ниже:

package com.vaidas.development.gradecalculatorbackend.repositories;

import com.vaidas.development.gradecalculatorbackend.models.Module;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class ModuleRepositoryTest {

    @Autowired
    private ModuleRepository moduleRepository;

    @Test
    @Transactional
    public void shouldInsertAndFindAll() {
        // GIVEN
        Module module = new Module("Test module", null);
        int count = moduleRepository.findAll().size();

        // WHEN
        moduleRepository.insertModule(module);
        int countAfter = moduleRepository.findAll().size();

        // THEN
        assertEquals(count,countAfter - 1);
    }

    @Test
    @Transactional
    public void shouldInsertAndFindOne() {
        // GIVEN
        Module module = new Module("Test module", null);
        module = moduleRepository.insertModule(module);

        // WHEN
        Module storedModule = moduleRepository.findOne(module.getId());

        // THEN
        assertEquals(storedModule.toString(), module.toString());
    }

    @Test
    @Transactional
    public void shouldUpdate() {
        // GIVEN
        Module module = new Module("Test module", null);
        module = moduleRepository.insertModule(module);
        Module updatedModule = new Module("Test module updated", null);
        updatedModule.setId(module.getId());

        // WHEN
        moduleRepository.updateModule(updatedModule);

        // THEN
        Module foundModule = moduleRepository.findOne(updatedModule.getId());
        assertEquals(foundModule.getName(), updatedModule.getName());
    }

    @Test
    @Transactional
    public void shouldDelete() {
        // GIVEN
        Module module = new Module("Test module", null);
        module = moduleRepository.insertModule(module);

        // WHEN
        moduleRepository.deleteModule(module);

        // THEN
        assertEquals(0, moduleRepository.findAll().size());
    }
}

Что я пробовал:

  • используя аннотации @DirtiesContext и @Transactional, которые, как я ожидал, сбросят содержимое БД
  • использование аннотаций @Before и @After для каждого теста, однако казалось, что они действовали асинхронно и не ждали, пока БД завершит добавление/удаление экземпляров

Неудачные тесты:

shouldInsertAndFindOne() {
shouldUpdate() {

Каждый из вышеперечисленных выдает следующую ошибку:

org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

Может ли кто-нибудь объяснить, почему это произошло и как правильно сбросить базу данных тестирования H2 перед каждым тестом?


person curiousdev    schedule 27.04.2019    source источник


Ответы (1)


Я не знаю, правильный ли это подход, но обычно я просто добавляю repositoryName.deleteAll() в @Before-аннотированный метод.

@Before
public void before() {
    moduleRepository.deleteAll();
    moduleRepository.flush();
}

Этот метод будет запускаться перед каждым из ваших @Test-аннотированных методов и гарантирует, что moduleRepository будет пустым.

Кроме того, эта аннотация @Transactional может быть источником вашей проблемы. Вы пробовали подход @Before без этой аннотации? Или как насчет добавления @Transactional на уровне класса?

person Misantorp    schedule 27.04.2019
comment
Спасибо за вашу помощь, но оказалось, что я не извлекал сгенерированный ключ из метода 'insertModule' в репозитории. Я присваивал возвращаемое значение метода NamedParameterJdbcTemplate.update, и теперь я использую GeneratedKeyHolder для его получения. Глупая моя ошибка. Кроме того, я использую @Transactional на уровне класса, чтобы откатить состояние БД до исходного. Спасибо за ваш вклад! - person curiousdev; 28.04.2019