嵌入式Redis与Spring Boot的结合

37

我使用本地Redis服务器帮助运行Spring Boot的集成测试用例。

但是我想要一个嵌入式Redis服务器,它不依赖于任何服务器,可以在任何环境下运行,就像H2内存数据库。我该怎么做呢?

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
@SpringApplicationConfiguration(classes = Application.class) 
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MasterIntegrationTest {

}

你有检查过 https://github.com/kstyrc/embedded-redis 吗? - Frederic Henri
1
是的,我已经检查过了,但我有点困惑,我的意思是我只想知道我是否需要创建@Bean RedisServer getserver(){}来注入它? - Gurinder
5个回答

49

你可以使用类似于 https://github.com/kstyrc/embedded-redis 的嵌入式 Redis。

  1. 将依赖添加到 pom.xml。
  2. 调整集成测试的属性以指向您的嵌入式 Redis,例如:

  3. spring:
      redis:
        host: localhost
        port: 6379
    
  4. 在仅定义于您的测试中的组件中实例化嵌入式Redis服务器:

  5. @Component
    public class EmbededRedis {
    
        @Value("${spring.redis.port}")
        private int redisPort;
    
        private RedisServer redisServer;
    
        @PostConstruct
        public void startRedis() throws IOException {
            redisServer = new RedisServer(redisPort);
            redisServer.start();
        }
    
        @PreDestroy
        public void stopRedis() {
            redisServer.stop();
        }
    }
    

1
有没有办法为嵌入式服务器设置密码? - Renjith
7
该项目似乎不再得到积极维护,最近一次更新已经接近两年前。 - Mads Hoel
10
https://github.com/ozimov/embedded-redis 是 https://github.com/kstyrc/embedded-redis 的后继者,我使用 ozimov/embedded-redis 添加了一个额外的答案。 - Markus Schulte
无法使用Redisson客户端,https://github.com/kstyrc/embedded-redis/issues/94 - Nitin
2
@Renjith 关于密码,我已经成功地使用.setting("requirepass " + redisPassword)进行了设置。这是使用ozimov版本完成的。 - KC Baltz
显示剩余7条评论

28
编辑:我现在强烈建议按照@magiccrafter的解释采用testcontainers方法,我现在也在我的测试中使用它。
你可以将ozimov/embedded-redis作为Maven(-test)依赖项使用(这是kstyrc/embedded-redis的继任者)。
  1. 将依赖项添加到您的pom.xml文件中

     <dependencies>
       ...
       <dependency>
         <groupId>it.ozimov</groupId>
         <artifactId>embedded-redis</artifactId>
         <version>0.7.1</version>
         <scope>test</scope>
       </dependency>
    
  2. 调整应用程序属性以进行集成测试

     spring.redis.host=localhost
     spring.redis.port=6379
    
  3. test configuration中使用嵌入式Redis服务器

     @TestConfiguration
     public static class EmbededRedisTestConfiguration {
    
       private final redis.embedded.RedisServer redisServer;
    
       public EmbededRedisTestConfiguration(@Value("${spring.redis.port}") final int redisPort) throws IOException {
         this.redisServer = new redis.embedded.RedisServer(redisPort);
       }
    
       @PostConstruct
       public void startRedis() {
         this.redisServer.start();
       }
    
       @PreDestroy
       public void stopRedis() {
         this.redisServer.stop();
       }
     }
    

5
这也没有被维护! - KitKarson
2
明智的做法是放弃使用未维护的embedded-redis。另一个回答建议使用testcontainers,现在应该成为被接受的解决方案。https://dev59.com/71wY5IYBdhLWcg3wh4Eq#50645865 - Sahil Jain
2
codemonstur/embedded-redisponfee/embedded-redissimbahebinbo/embedded-redissignalapp/embedded-redis 是最近更新的 embedded-redis 分支。它们之间存在一些差异,例如只有前两个支持 Windows。 - gebi

13

另一种很好的方法是使用testcontainers库,它可以在Docker容器中运行任何类型的应用程序,包括Redis。我最喜欢的是它与Spring测试生态系统的耦合度较低。

Maven依赖:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>${testcontainers.version}</version>
</dependency>

简单的集成测试:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
@DirtiesContext
public abstract class AbstractIntegrationTest {

    private static int REDIS_PORT = 6379;

    @ClassRule
    public static GenericContainer redis = new GenericContainer("redis:5-alpine").withExposedPorts(REDIS_PORT);

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext ctx) {
            // Spring Boot 1.5.x
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx,
                "spring.redis.host=" + redis.getContainerIpAddress(),
                "spring.redis.port=" + redis.getMappedPort(REDIS_PORT));

            // Spring Boot 2.x.
            TestPropertyValues.of(
                "spring.redis.host:" + redis.getContainerIpAddress(),
                "spring.redis.port:" + redis.getMappedPort(REDIS_PORT))
                .applyTo(ctx);
        }
    }
}

从Spring Framework 5.2.5(Spring Boot 2.3.x)开始,你可以使用强大的DynamicPropertySource注解。以下是一个示例:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public abstract class AbstractIT {

    static GenericContainer redisContainer = new GenericContainer("redis:5-alpine").withExposedPorts(6379);

    @DynamicPropertySource
    static void properties(DynamicPropertyRegistry r) throws IOException {
        r.add("spring.redis.host", redisContainer::getContainerIpAddress);
        r.add("spring.redis.port", redisContainer::getFirstMappedPort);
    }
}

根据我们使用的测试容器库,有没有办法知道Redis容器镜像的名称? - Paramesh Korrakuti

1

您可以查看此存储库:https://github.com/caryyu/spring-embedded-redis-server,与Spring和Spring Boot完全集成

Maven依赖项

<dependency>
<groupId>com.github.caryyu</groupId>
<artifactId>spring-embedded-redis-server</artifactId>
<version>1.1</version>
</dependency>

Spring Boot注解

@Bean
public RedisServerConfiguration redisServerConfiguration() {
return new RedisServerConfiguration();
}

应用程序.yml的使用
spring:
    redis:
        port: 6379
        embedded: true

代码库文档是用中文编写的,如果您找到了英文版本,请贴上链接。 - Roshana Pitigala
2
这个项目基本上是接受答案中提到的那个项目的包装器。毫无意义。 - fer.marino

1
如果您正在使用Spring和Reactive来响应式地访问Redis数据,也就是说您有一个ReactiveRedisConnectionFactory(带有RedisConnectionFactory bean)和一个LettuceConnectionFactory,那么您可能想要采用以下方法为多个测试类设置嵌入式Redis。
首先,将playtika嵌入式Redis添加到您的依赖项中:
dependencies {
    testCompile("com.playtika.testcontainers:embedded-redis:2.0.9")
}

然后在你的 application.yml 中将 Redis 主机和端口设置为嵌入式 Redis 生成的 embedded.redis 环境变量。

spring:
  redis:
    host: \${embedded.redis.host:localhost}
    port: \${embedded.redis.port:6739}

bootstrap-redisnoauth.properties 文件中,设置环境变量 embedded.redis.requirepass=false,以便它不需要密码。
然后在您的测试中使用活动配置文件:
@ActiveProfiles("redisnoauth")

同时确保在你的测试类中也有这个@TestConfiguration,这样将会连接到在随机生成的端口上启动的 Redis。

@Category(IntegrationTest.class)
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("redisnoauth")
public class RedisCacheTest {

    @TestConfiguration
    static class RedisTestConfiguration {
    
        @Bean
        public RedisConnectionFactory redisConnectionFactory(@Value("${spring.redis.host}") String host,
                                                             @Value("${spring.redis.port}") int port) {
            return new LettuceConnectionFactory(host, port);
        }
    
        @Bean
        public RedisOperations<String, String> stringKeyAndStringValueRedisOperations(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.setKeySerializer(new StringRedisSerializer(UTF_8));
            redisTemplate.setValueSerializer(new StringRedisSerializer(UTF_8));
            return redisTemplate;
        }
    }

    @Test
    public void myTest() {
      // your test
    }

}

而且它应该能够顺畅地工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接