0

我使用 Spring Boot、TestContainers、redis 和 Junit 5 进行集成测试。我遇到了一个奇怪的行为,当我进行所有集成测试时,我一直在显示这个日志:

无法重新连接到 [localhost:55133]:连接被拒绝:localhost/127.0.0.1:55133

这个例外:

org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 1 minute(s)

at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70)

但是我单独运行测试,我没有这种行为。

我使用 Junit5,我正在使用 Junit5 扩展来启动和停止我的 redis 容器:

public class RedisTestContainerExtension implements BeforeAllCallback, AfterAllCallback {

    private GenericContainer<?> redis;

    @Override
    public void beforeAll(ExtensionContext extensionContext) throws Exception {
        redis = new GenericContainer<>(DockerImageName.parse("redis:5.0.3-alpine"))
                .withCommand("redis-server","--requirepass", "password")
                .waitingFor(Wait.forListeningPort())
                .withStartupTimeout(Duration.ofMinutes(2))
                .withExposedPorts(6379);
        redis.start();
        System.setProperty("APP_REDIS_CONVERSATIONS_HOST",redis.getHost());
        System.setProperty("APP_REDIS_CONVERSATIONS_PORT",redis.getFirstMappedPort().toString());
        System.setProperty("APP_REDIS_CONVERSATIONS_PASSWORD","password");
        System.setProperty("APP_REDIS_CONVERSATIONS_TTL","600m");
    }

    @Override
    public void afterAll(ExtensionContext extensionContext) throws Exception {
        if(redis != null){
            redis.stop();
        }
    }
}

我将此文件添加为我的集成测试的扩展:

@ExtendWith({SpringExtension.class, RedisTestContainerExtension.class})
@SpringBootTest(classes = ConversationsApplication.class)
class MyIntegrationTest {
 ...
 }

谁能帮我解决这种情况。

4

1 回答 1

0

我们有一个类似的问题。仅当我们执行所有测试(或至少不仅仅是一个特定的测试)时才会出现此问题

我们有另一个测试设置 - 我们使用基类来管理测试测试容器 - 通过 DynamicPropertySource 覆盖属性来应用容器的端口映射

我们的解决方法是用@DirtiesContext标记基本测试类,Spring 不会在测试类上重用应用程序上下文 - 请参阅 DynamicPropertySource 的文档:

注意:如果您在基类中使用 @DynamicPropertySource 并发现子类中的测试由于子类之间的动态属性更改而失败,您可能需要使用 @DirtiesContext 注释您的基类,以确保每个子类都有自己的 ApplicationContext 具有正确的动态特性。

例子:

@Slf4j
@SpringBootTest
@DirtiesContext
@Testcontainers
public abstract class AbstractContainerTest {

  @Container
  private static final ElasticsearchContainer elasticsearchContainer = new DealElasticsearchContainer();

  @Container
  private static final RedisCacheContainer redisCacheContainer = new RedisCacheContainer();

  @DynamicPropertySource
  static void databaseProperties(DynamicPropertyRegistry registry) {
    log.info("Override properties to connect to Testcontainers:");
    log.info("* Test-Container 'Elastic': spring.elasticsearch.rest.uris = {}",
        elasticsearchContainer.getHttpHostAddress());
    log.info("* Test-Container 'Redis': spring.redis.host = {} ; spring.redis.port = {}",
        redisCacheContainer.getHost(), redisCacheContainer.getMappedPort(6379));

    registry.add("spring.elasticsearch.rest.uris", elasticsearchContainer::getHttpHostAddress);
    registry.add("spring.redis.host", redisCacheContainer::getHost);
    registry.add("spring.redis.port", () -> redisCacheContainer.getMappedPort(6379));
  }

}

因此,也许可以尝试使用 @DirtiesContext 或切换到使用 DynamicPropertySource 覆盖属性的设置。它是专门为这种情况而构建的:

需要将具有动态值的属性添加到 Environment 的一组 PropertySources 的集成测试的方法级注释。

此注解及其支持基础设施最初旨在允许基于 Testcontainers 的测试的属性轻松地暴露给 Spring 集成测试。但是,此功能也可以用于任何形式的外部资源,其生命周期在测试的 ApplicationContext 之外维护。

于 2022-02-02T10:16:38.470 回答