Миссия Spring Data — предоставить знакомую и согласованную модель программирования на основе Spring для доступа к данным, сохраняя при этом особые черты основного хранилища данных. Он обеспечивает интеграцию с несколькими базовыми технологиями, такими как JPA, Rest, MongoDB, Neo4J или Redis.
Так что, если вы используете Spring (Boot), то Spring Data — правильный выбор для работы со слоем постоянства.
В следующем примере вы можете увидеть, как просто использовать Spring Boot и Spring Data Redis .
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
|
@Controller @EnableAutoConfiguration public class PingPongController { @Autowired StringRedisTemplate redisTemplate; @RequestMapping ( "/{ping}" ) @ResponseBody List<String> getPong( @PathVariable ( "ping" ) String ping) { final ListOperations<String, String> stringStringListOperations = redisTemplate.opsForList(); final Long size = stringStringListOperations.size(ping); return stringStringListOperations.range(ping, 0 , size); } @RequestMapping (value= "/{ping}" , method = RequestMethod.POST) ResponseEntity<?> addPong( @PathVariable ( "ping" ) String ping, @RequestBody String pong) { final ListOperations<String, String> stringStringListOperations = redisTemplate.opsForList(); stringStringListOperations.leftPushAll(ping, pong); URI location = ServletUriComponentsBuilder .fromCurrentRequest() .buildAndExpand(ping).toUri(); return ResponseEntity.created(location).build(); } public static void main(String[] args) { SpringApplication.run(PingPongController. class , args); } } |
1
2
3
4
5
6
7
8
9
|
@Configuration public class RedisConfiguration { @Bean StringRedisTemplate template( final RedisConnectionFactory connectionFactory) { return new StringRedisTemplate(connectionFactory); } } |
Важно отметить, что по умолчанию Spring Data Redis настроен для подключения к localhost и порту 6379 , но вы можете переопределить эти значения, установив системные свойства ( spring.redis.host и spring.redis.port ) или переменные среды ( SPRING_REDIS_HOST и SPRING_REDIS_PORT ).
Но теперь пришло время написать тест для этого куска кода. Основная проблема, с которой вы можете столкнуться, заключается в том, что вам нужен сервер Redis, установленный на всех машинах, которые должны выполнять эти тесты, таких как машины разработчиков или подчиненные Jenkins.
Само по себе это не проблема, но когда вы начнете работать над все большим количеством проектов, вам понадобится установить все больше и больше баз данных в системе, и, что еще хуже, это будет не совсем та же версия, которая требуется для работы.
Чтобы избежать этой проблемы, одним из возможных решений является использование Docker и контейнеров. Таким образом, вместо того, чтобы устанавливать каждую базу данных в системе, вы зависите только от Docker . Затем тест просто запускает контейнер репозитория, в нашем случае Redis, выполняет тест (ы) и, наконец, останавливает контейнер.
И именно здесь Arquillian (и Arquillian Cube ) помогают вам автоматизировать все.
Arquillian Cube — это расширение Arquillian, которое можно использовать для управления контейнерами Docker из Arquillian.
Чтобы использовать Arquillian Cube, вам нужен демон Docker , работающий на компьютере (он может быть локальным или нет), но, вероятно, он будет локальным.
По умолчанию сервер Docker использует сокеты UNIX для связи с клиентом Docker . Arquillian Cube попытается определить операционную систему, в которой он работает, и либо установить docker-java для использования сокета UNIX в Linux или Boot2Docker / Docker-Machine в Windows / Mac в качестве URI по умолчанию , поэтому ваш тест переносим для нескольких установок Docker и вам не нужно беспокоиться о его настройке, Arquillian Cube адаптируется к тому, что вы установили.
Arquillian Cube предлагает три различных способа определения контейнера (ов).
- Определение файла docker-compose .
- Определение объекта-контейнера .
- Использование контейнерного объекта DSL .
Для этого поста используется контейнерный объект DSL. Чтобы определить контейнер, который должен быть запущен до выполнения тестов и остановлен после того, как вам нужно будет написать только следующий фрагмент кода.
1
2
3
|
@ClassRule public static ContainerDslRule redis = new ContainerDslRule( "redis:3.2.6" ) .withPortBinding( 6379 ); |
В этом случае правило JUnit используется, чтобы определить, какое изображение следует использовать в тесте ( redis: 3.2.6 ), и добавить в качестве связующего порта порт Redis ( 6379 ).
Полный тест выглядит так:
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 ) ); } } } |
Обратите внимание, что это простой тест Spring Boot с использованием их битов и бобов, но в тесте используется правило JQnit Arquillian Cube для запуска и остановки образа Redis.
Последнее, что следует отметить, это то, что test содержит реализацию ApplicationContextInitializer, поэтому мы можем сконфигурировать среду с данными Docker (хост и порт привязки контейнера Redis), чтобы Spring Data Redis мог подключиться к правильному экземпляру.
Последний, но не менее важный файл build.gradle определяет необходимые зависимости, которые выглядят так:
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
|
buildscript { repositories { jcenter() mavenCentral() } dependencies { classpath( "org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE" ) } } plugins { id "io.spring.dependency-management" version "1.0.2.RELEASE" } apply plugin: 'java' apply plugin: 'org.springframework.boot' repositories { jcenter() } project.version = '1.0.0' dependencyManagement { imports { mavenBom 'org.jboss.arquillian:arquillian-bom:1.1.13.Final' } } dependencies { compile "org.springframework.boot:spring-boot-starter-web:1.5.2.RELEASE" compile 'org.springframework.boot:spring-boot-starter-data-redis:1.5.2.RELEASE' testCompile 'org.springframework.boot:spring-boot-starter-test:1.5.2.RELEASE' testCompile 'junit:junit:4.12' testCompile 'org.arquillian.cube:arquillian-cube-docker-junit-rule:1.2.0' testCompile 'org.assertj:assertj-core:3.6.2' } |
Ссылка: | Тестирование приложений Spring Data + Spring Boot с Arquillian (часть 1) от нашего партнера по JCG Алекса Сото в блоге One Jar To Rule All . |