В предыдущем посте я писал о том, как тестировать приложение Spring Data с помощью Docker с Arquillian Cube . Тест выглядел так:
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
|
@RunWith (SpringRunner. class ) @SpringBootTest (classes = PingPongController. class , webEnvironment = RANDOM_PORT) @ContextConfiguration (initializers = PingPongSpringBootTest.Initializer. class ) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule( "redis:3.2.6" ) .withPortBinding( 6379 ); @Autowired TestRestTemplate restTemplate; @Test public void should_get_pongs() { // given restTemplate.postForObject( "/ping" , "pong" , String. class ); restTemplate.postForObject( "/ping" , "pung" , String. class ); // when final List<String> pings = restTemplate.getForObject( "/ping" , List. class ); // then assertThat(pings) .hasSize( 2 ) .containsExactlyInAnyOrder( "pong" , "pung" ); } public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { EnvironmentTestUtils.addEnvironment( "testcontainers" , configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort( 6379 ) ); } } } |
Этот тест просто запускает контейнер Redis , затем заполняет данные, используя restTemplate и метод post , затем выполняет тестируемую логику (тестирование метода GET HTTP ) и, наконец, останавливает контейнер Redis .
Это хорошо, это работает, но есть несколько проблем:
- Во-первых, мы используем REST API для подготовки набора данных теста. Проблема здесь в том, что тест может завершиться неудачей не из-за сбоя тестируемого кода, а из-за подготовки теста (вставка данных).
- Во-вторых, если конечная точка POST меняет формат / местоположение, вам нужно помнить об изменении везде в тестах, где она используется.
- Последнее заключается в том, что каждый тест должен покидать среду, которая была найдена до выполнения, поэтому тест изолирован от всех выполнений. Проблема в том, что для этого нужно удалить предыдущие элементы, вставленные методом POST . Это означает, что нужно добавить метод УДАЛИТЬ HTTP, который не всегда может быть реализован в конечной точке, или он может быть ограничен некоторыми конкретными пользователями, поэтому необходимо иметь дело со специальными средствами аутентификации.
Чтобы избежать этой проблемы, было создано Arquillian Persistence Extension (aka APE ). Это расширение интегрируется с DBUnit и Flyway для баз данных SQL , NoSQLUnit для баз данных без SQL и коллекциями Postman для служб REST, так что вы можете заполнить свой бэкэнд перед тестированием реального варианта использования теста и очистить постоянное хранилище после его выполнения.
Также данные о населении хранятся внутри файла, что означает, что их можно использовать повторно во всех тестах и легко изменять в случае любого обновления схемы.
Давайте посмотрим на пример части 1 поста, но обновляем, чтобы использовать APE .
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
|
@RunWith (SpringRunner. class ) @SpringBootTest (classes = PingPongController. class , webEnvironment = RANDOM_PORT) @ContextConfiguration (initializers = PingPongSpringBootTest.Initializer. class ) public class PingPongSpringBootTest { @ClassRule public static ContainerDslRule redis = new ContainerDslRule( "redis:3.2.6" ) .withPortBinding( 6379 ); @Rule public ArquillianPersistenceRule arquillianPersistenceRule = new ArquillianPersistenceRule(); @Autowired TestRestTemplate restTemplate; @Redis @ArquillianResource NoSqlPopulator populator; @Test public void should_get_pongs() { // given populator.forServer(redis.getIpAddress(), redis.getBindPort( 6379 )) .usingDataSet( "pings.json" ) .execute(); // when final List<String> pings = restTemplate.getForObject( "/ping" , List. class ); // then assertThat(pings) .hasSize( 2 ) .containsExactlyInAnyOrder( "pong" , "pung" ); } @After public void clean_database() { populator.forServer(redis.getIpAddress(), redis.getBindPort( 6379 )) .clean(); } public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { EnvironmentTestUtils.addEnvironment( "testcontainers" , configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort( 6379 ) ); } } } |
И файл ( pings.json ), используемый для заполнения экземпляра Redis данными, выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
{ "data" : [ { "list" : [ { "key" : "ping" , "values" : [ { "value" : "pong" }, { "value" : "pung" } ] } ] } ] } |
Проект можно найти по адресу https://github.com/arquillian-testing-microservices/pingpongbootredis.
Ссылка: | Тестирование приложений Spring Data + Spring Boot с Arquillian (часть 2) от нашего партнера JCG Алекса Сото в блоге One Jar To Rule All . |