开发者社区 问答 正文

无法自动连线WebTestClient

我试图注入一个WebTestClient,以使用Spring Webflux实现一些集成测试。

我必须加载使用此配置运行的redis嵌入式软件:

@Configuration
@Profile("test")
public class EmbeddedRedisConfiguration {

    private RedisServer redisServer;

    public EmbeddedRedisConfiguration(@Value("${spring.redis.port}") int redisPort) {
        this.redisServer = new RedisServer(redisPort);
    }

    @PostConstruct
    public void postConstruct() {
        redisServer.start();
    }

    @PreDestroy
    public void preDestroy() {
        redisServer.stop();
    }

    @Bean
    @Primary
    public ReactiveRedisOperations<String, Foo> redisOperations(@Qualifier("redissonConnectionFactory") ReactiveRedisConnectionFactory factory) {

        Jackson2JsonRedisSerializer<Foo> serializer = new Jackson2JsonRedisSerializer<>(Foo.class);
        RedisSerializationContext.RedisSerializationContextBuilder<String, Foo> builder = RedisSerializationContext.newSerializationContext(new StringRedisSerializer());
        RedisSerializationContext<String, Foo> context = builder.value(serializer).build();

        return new ReactiveRedisTemplate<>(factory, context);
    }
}

上课

@ExtendWith(SpringExtension.class)
@SpringBootTest
@ActiveProfiles("test")
public class FooControllerIT {

    @Autowired
    WebTestClient webTestClient;

    @Test
    public void testSomething() {
          // do something
    }
}

我收到此错误:

No qualifying bean of type 'org.springframework.test.web.reactive.server.WebTestClient' available: expected at least 1 bean which qualifies as autowire candidate

如果我改变这一行

@SpringBootTest

到这条线

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

WebTestClient可用于自动装配,但是应用程序会在我的测试配置文件配置之前启动,无法连接到嵌入式Redis:

Factory method 'redisson' threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

有没有注入WebTestClient而不启动web环境的方法,还是有办法在其他事情之前加载我的嵌入式redis配置?

编辑

看来问题是那js RedissonAutoConfiguration 是

展开
收起
垚tutu 2019-11-29 23:18:33 1625 分享 版权
阿里云 AI 助理回答

在Spring Boot测试中,使用@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)确实会启动一个完整的Web服务器,这可能与你希望先初始化嵌入式Redis再进行其他服务启动的顺序相冲突。为了解决这个问题,你可以采取以下策略:

1. 使用Testcontainers

Testcontainers 是一个强大的库,允许在JUnit测试中运行轻量级的 Docker 容器。对于你的需求,可以使用 Redis Testcontainer 来确保 Redis 在所有其他服务之前启动。

首先,添加 Testcontainers 的依赖到你的项目中(Maven 示例):

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>redis</artifactId>
    <scope>test</scope>
</dependency>

然后,在测试类中使用 Testcontainers 初始化 Redis:

@SpringBootTest
@ActiveProfiles("test")
public class FooControllerIT {

    static {
        GenericContainer<?> redis = new GenericContainer<>("redis:latest")
            .withExposedPorts(6379);
        redis.start();
        System.setProperty("spring.redis.host", redis.getHost());
        System.setProperty("spring.redis.port", String.valueOf(redis.getMappedPort(6379)));
    }

    @Autowired
    private WebTestClient webTestClient;

    // ... 测试方法
}

这样,每次测试运行时,都会先启动一个 Redis 容器,并设置相应的环境变量供Spring应用使用,确保了Redis在应用启动前已经就绪。

2. 自定义TestExecutionListener

如果你不想使用Docker和Testcontainers,可以通过自定义TestExecutionListener来控制Spring Boot应用程序的启动顺序,确保Redis配置在Web服务器启动之前完成初始化。

创建一个监听器类,覆盖beforeTestClass方法来启动RedisServer:

public class EmbeddedRedisStartupListener extends AbstractTestExecutionListener {

    @Override
    public void beforeTestClass(TestContext testContext) throws Exception {
        ConfigurableApplicationContext context = testContext.getApplicationContext();
        EmbeddedRedisConfiguration config = context.getBean(EmbeddedRedisConfiguration.class);
        config.postConstruct(); // 手动启动RedisServer
    }
}

然后,在测试类上使用@TestExecutionListeners注解指定这个监听器:

@TestExecutionListeners(listeners = {EmbeddedRedisStartupListener.class, DependencyInjectionTestExecutionListener.class})
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class FooControllerIT {
    // ... 测试代码
}

这种方法需要手动控制RedisServer的生命周期,确保它在测试结束时被正确关闭。

结论

上述两种方法都能帮助你在不直接启动Web环境的情况下注入WebTestClient,同时确保嵌入式Redis配置得以正确加载。Testcontainers提供了一种更加隔离且灵活的解决方案,而自定义TestExecutionListener则是一种更直接介入Spring测试生命周期的方法。根据你的具体需求和偏好选择合适的方法。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答