Spring Boot Test,在配置中注入值

Posted

技术标签:

【中文标题】Spring Boot Test,在配置中注入值【英文标题】:SpringBoot Test, inject value in configuration 【发布时间】:2020-10-04 14:20:01 【问题描述】:

我想做什么:

从测试容器https://github.com/testcontainers/testcontainers-spring-boot/tree/develop/embedded-mongodb启动MongoDB容器 将从已启动容器中获取的 MongoDB uri 注入到配置中 运行测试

这是我的代码:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = 
        "embedded.mongodb.install.enabled=true",
        "spring.data.mongodb.uri=mongodb://$embedded.mongodb.host:$embedded.mongodb.port/$embedded.mongodb.database"
)
@AutoConfigureMockMvc
@ImportAutoConfiguration
class UploadFileControllerTest 

    @LocalServerPort
    private int port;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    private static MongoDBContainer mongoDbContainer;

    @BeforeAll
    public static void startContainer() 
        mongoDbContainer = new MongoDBContainer();

        mongoDbContainer.start();
        // !!! this one should be injected into spring.data.mongodb.uri
        System.out.println("mongoURL: " + mongoDbContainer.getReplicaSetUrl());
        // !!!
    

    @AfterAll
    public static void stopContainer() 
        mongoDbContainer.stop();
    

    @Test
    void testUploadAndParseFile() throws Exception 
        var fileUploadTask = uploadFileUsingMockMvc(zipFile);
        System.out.println(fileUploadTask);
    

我找不到填充 spring.data.mongodb.uri 配置值的方法。

【问题讨论】:

查看baeldung.com/spring-boot-embedded-mongodb 我想要真正的 :) 【参考方案1】:

当您使用 JUnit 5 时,您可以为 Testcontainers 使用 JUnit Jupiter 扩展,因此您不必手动启动和停止它们(如 JUnit 4 中的 @ClassRule):

<dependency>
  <groupId>org.testcontainers</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>$testcontainers.version</version>
  <scope>test</scope>
</dependency>

如果您使用 Spring Boot >= 2.2.6,他们甚至使用 @DynamicPropertySource 简化了在测试中动态设置属性的方法。

如果将两者结合起来,您的测试可能如下所示:

// @ExtendWith(SpringExtension.class) not needed, already part of @SpringBootTest
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ImportAutoConfiguration
@Testcontainers // this is new
class UploadFileControllerTest 

    @LocalServerPort
    private int port;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Container
    private static MongoDBContainer mongoDbContainer = new MongoDBContainer();

    @DynamicPropertySource
    static void mongoDbProperties(DynamicPropertyRegistry registry) 
      registry.add("spring.data.mongodb.uri", mongoDbContainer::getUri);
    


    @Test
    void testStuffWithMongo() throws Exception 
     // bla-bla-bla
    

如果你使用的是 JUnit 4 或 Spring Boot 2.2.6 之前的版本,我收集了不同的设置方法here。

【讨论】:

【参考方案2】:

这是我的解决方案,因为它具有全局静态状态,所以有点味道,但至少可以工作

包装容器

public class MongoDbContainerEntryPoint 

    private static MongoDBContainer mongoDbContainer = new MongoDBContainer();

    public static void start() 
        mongoDbContainer.start();
    

    public static void stop() 
        mongoDbContainer.stop();
    

    public static String getUri() 
        return mongoDbContainer.getReplicaSetUrl();
    

这个东西允许在测试实例化期间覆盖属性

public class MongoDBContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext> 

    @Override
    public void initialize(ConfigurableApplicationContext ac) 

        ConfigurableEnvironment ce = ac.getEnvironment();
        System.out.println("Setting to configuration: " + MongoDbContainerEntryPoint.getUri());
        TestPropertyValues values = TestPropertyValues.of(
                "spring.data.mongodb.uri=" + MongoDbContainerEntryPoint.getUri()
        );
        values.applyTo(ac);
    

这是测试

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = MongoDBContextInitializer.class)
@AutoConfigureMockMvc
@ImportAutoConfiguration
class UploadFileControllerTest 

    @LocalServerPort
    private int port;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;


    @BeforeAll
    public static void startContainer() 
        MongoDbContainerEntryPoint.start();
    

    @AfterAll
    public static void stopContainer() 
        MongoDbContainerEntryPoint.stop();
    

    @Test
    void testStuffWithMongo() throws Exception 
     // bla-bla-bla
    

【讨论】:

以上是关于Spring Boot Test,在配置中注入值的主要内容,如果未能解决你的问题,请参考以下文章

spring-boot -配置文件值注入

spring-boot-test spyBean 注解不注入依赖

spring boot 配置注入

spring boot test中如何配置HandlerMethodArgumentResolver

记录Spring Boot大坑一个,在bean中如果有@Test单元测试,不会注入成功

spring boot 项目属性配置