Junit Spring избегает двойной загрузки источника данных контекста приложения - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть следующие классы конфигурации:

@ComponentScan(
        basePackages = { 
                "mypackage.controller",
                "mypackage.service",
                "mypackage.repository" 
        }
)
@TestPropertySource(locations="classpath:configuration.properties")
@Import({
    H2Configuration.class
})
public class TestConfiguration {
}

@Configuration
public class H2Configuration {

    @Bean
    public DataSource dataSource() throws SQLException {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase db = builder
                .setType(EmbeddedDatabaseType.H2)
                .addScript("h2/create.sql")
                .addScript("h2/insert.sql")
                .build();
        db.getConnection().setAutoCommit(false);
        return db;
    }

}

И у меня есть два теста классов:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = { TestConfiguration.class })
public class FirstRepositoryTest {

    @Autowired
    MyFirstRepositoryImpl repository;

    @Before
    public void initTest() {
    }

    @Test(expected = NullPointerException.class)
    public void testNullRecords() {
        repository.foo(null, null);
    }
}


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = { TestConfiguration.class })
public class SecondRepositoryTest {

    @Autowired
    MySecondRepositoryImpl repository;

    @Before
    public void initTest() {
    }

    @Test(expected = NullPointerException.class)
    public void testSomethingNullRecords() {
        repository.something(null, null);
    }
}

Если я запускаю тест джунита один раз для каждого класса, все идет хорошо.

В фазе чистой установки тестирование завершается неудачно, поскольку контекст приложения инициализируется дважды.

Например, он пытается дважды создать таблицы h2 и дважды выполнить скрипт insert.sql.

Что мне нужно сделать, чтобы инициализировать базу данных h2 и, следовательно, контекст приложения только один раз?

Спасибо

Ответы [ 4 ]

0 голосов
/ 07 февраля 2019

Еще один хороший совет, который я нашел из Spring Boot Документация Поддержка встроенных баз данных :

Они говорят:

Если выИспользуя эту функцию в своих тестах, вы можете заметить, что одна и та же база данных повторно используется всем вашим набором тестов, независимо от количества используемых вами контекстов приложения.Если вы хотите убедиться, что у каждого контекста есть отдельная встроенная база данных, вы должны установить для spring.datasource.generate-unique-name значение true.

Таким образом, чтобы сделать каждый EmbeddedDatabase уникальным, вы можетепопробуйте создать их с помощью:

EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
                      .generateUniqueName(true)
                      ...
                      .build();
0 голосов
/ 07 февраля 2019

Я думаю, вы могли бы начать смотреть на документацию Spring о Интеграционное тестирование .

Хорошей практикой может быть также использование транзакционных тестов для интеграционных тестов (@Transactional), которыеоткат в конце каждого теста: см. Управление транзакциями .

Чтобы избежать затрат на воссоздание ApplicationContext для каждого класса теста, можно использовать кэш, как описано здесь: Контекстное кэширование .

Для интеграционного тестирования с Встроенная база данных вы также можете найти документацию: Тестирование логики доступа к данным со встроенной базой данных .Примечание из предыдущей ссылки, соответствующее вашему варианту использования:

Однако, если вы хотите создать встроенную базу данных, которая является общей для набора тестов, рассмотрите возможность использования Spring TestContext Framework и настройки встроенной базы данных.как bean-компонент в Spring ApplicationContext, как описано в разделе Создание встроенной базы данных с использованием Spring XML и создание встроенной базы данных программным способом.

Надеюсь, вы найдете несколько полезных ссылок.

0 голосов
/ 07 февраля 2019

В модульном тестировании вы должны гарантировать, что каждый тест не зависит от контекста повторяемости.Из-за этого не стоит загружать контекст только один раз.Лучше всего сбросить после выполнения.Для этого вы можете использовать @ DirtiesContext (classMode = ClassMode.AFTER_CLASS) в ваших тестовых классах

Таким образом, вы заставите ваш контекст перезапуститься при запуске следующего класса junit

0 голосов
/ 07 февраля 2019

Таким образом, причина этого заключается в том, что база данных (H2) находится в памяти, когда вы запускаете тесты как часть clean / install.Сценарии создания / вставки уже выполнены после запуска первого теста.Любое последующее выполнение теста после этой точки приведет к повторному выполнению тех же сценариев и возникнет ошибка.

Обновите сценарий создания с помощью DROP TABLE IF EXISTS <table name>;.Это обеспечит удаление таблицы и ее повторное создание.

ПРИМЕЧАНИЕ : я не уверен, почему вы указали AnnotationConfigContextLoader явно.Я думаю, без этого бегун SpringJUnit4ClassRunner будет кешировать контексты, которые не были изменены.Я точно не знаю, так ли это здесь.

...