有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

用于Spring Boot的java嵌入式Redis

我在机器上的本地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 {

}

共 (3) 个答案

  1. # 1 楼答案

    你可以使用像https://github.com/kstyrc/embedded-redis这样的嵌入式Redis

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

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

      @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();
          }
      }
      
  2. # 2 楼答案

    另一个好方法是使用testcontainers库,它可以运行任何类型的应用程序,这些应用程序可以在Docker容器中运行,Redis也不例外。我最喜欢的是它与Spring Test生态系统的结合

    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);
        }
    }
    
  3. # 3 楼答案

    如果您正在使用spring并对access data with redis reactively进行反应。 这意味着你有一个ReactiveRedisConnectionFactory(带有一个RedisConnectionFactorybean)和一个LettuceConnectionFactory,那么你可能想要按照这种方法为多个测试类设置一个嵌入式redis

    首先将playtika embedded redis添加到依赖项中:

    dependencies {
        testCompile("com.playtika.testcontainers:embedded-redis:2.0.9")
    }
    

    然后在应用程序中将redis主机和端口设置为embedded.redis。yml(由嵌入式redis在创建时作为env变量生成)

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

    bootstrap-redisnoauth.properties文件中,设置env变量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
        }
    
    }
    

    而且它应该工作顺利