Spring Data的使命是为数据访问提供一个熟悉且一致的,基于Spring的编程模型,同时仍保留基础数据存储的特殊特征。 它提供了与一些后端技术的集成,例如JPA,Rest,MongoDB,Neo4J或Redis。
因此,如果您使用的是Spring(引导),那么Spring Data是处理持久层的正确选择。
在下一个示例中,您可以看到使用Spring Boot和Spring Data Redis有多么简单。
@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);
}
}
@Configuration
public class RedisConfiguration {
@Bean
StringRedisTemplate template(final RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
这是通知,缺省时,Spring数据Redis的配置连接到本地主机和端口6379的重要,但是你可以重写通过设置系统属性(spring.redis.host和spring.redis.port)或环境变量这些值(SPRING_REDIS_HOST和SPRING_REDIS_PORT )。
但是现在是时候为这段代码编写测试了。 您可能会遇到的主要问题是,需要在所有需要执行这些测试的机器(例如开发人员机器或Jenkins从站)中安装Redis服务器。
这本身不是问题,但是当您开始处理越来越多的项目时,您将需要在系统上安装越来越多的数据库,甚至更糟糕的是,与生产所需的版本也不完全相同。
为了避免这个问题,一种可能的解决方案是使用Docker和容器。 因此,您无需依赖于在系统上安装每个数据库,而仅依赖Docker 。 然后,测试仅启动存储库容器,在我们的示例中为Redis,执行测试,最后停止容器。
这就是Arquillian (和Arquillian Cube )在帮助您自动化所有事情的地方。
Arquillian Cube是Arquillian扩展,可用于管理Arquillian的 Docker容器。
要使用Arquillian Cube,您需要在计算机上运行Docker守护程序(它可以是本地的,也可以不是本地的),但是可能是在本地。
默认情况下, Docker服务器使用UNIX套接字与Docker客户端进行通信。 Arquillian Cube将尝试检测其正在运行的操作系统,并将docker -java设置为在Linux上使用UNIX套接字,或者将Windows / Mac上的Boot2Docker / Docker-Machine设置为默认URI,因此您的测试可在多个Docker安装之间移植而且您无需担心对其进行配置, Arquillian Cube可以适应您所安装的内容。
Arquillian Cube提供了三种定义容器的不同方法。
- 定义docker-compose文件。
- 定义一个容器对象 。
- 使用容器对象DSL 。
在本文中,使用的是Container Object DSL方法。 要定义一个容器,该容器将在执行测试之前启动,而在编写后仅需编写一段代码后停止。
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
.withPortBinding(6379);
在这种情况下,将使用JUnit规则来定义测试中应使用的映像( redis:3.2.6 ),并将Redis端口( 6379 )添加为绑定端口。
完整的测试如下所示:
@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测试,但是测试中使用Arquillian Cube JUnit Rule来启动和停止Redis映像。
需要注意的最后一件事是测试包含ApplicationContextInitializer的实现,因此我们可以使用Docker数据(Redis容器的主机和绑定端口)配置环境,以便Spring Data Redis可以连接到正确的实例。
最后但并非最不重要的build.gradle文件定义所需的依赖项,如下所示:
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'
}