我想在 Spring Boot 集成测试中创建 bean 之前模拟服务器

Posted

技术标签:

【中文标题】我想在 Spring Boot 集成测试中创建 bean 之前模拟服务器【英文标题】:I want to mock a server before bean creation in spring boot integration test 【发布时间】:2020-01-15 02:24:06 【问题描述】:

我正在 spring-boot 中编写集成测试。 我的 bean 之一是使用 UrlResource("http://localhost:8081/test") 进行创建。 我想创建一个模拟服务器,它将为上述 url 提供模拟响应。 但我希望在初始化任何 bean 之前创建这个模拟服务器,因为模拟服务器应该可以在 bean 初始化之前为请求提供服务。

我尝试在 @TestConfiguration 中使用 MockRestServiceServer

以下是失败的伪代码:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestApiGatewayApplicationTests 

    @Autowired
    private TestRestTemplate restTemplate;


    @Test
    public void contextLoads() 

    

    @TestConfiguration
    class TestConfig 

        @Bean
        public RestTemplateBuilder restTemplateBuilder() 
            RestTemplate restTemplate = new RestTemplate();
            MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
            String mockKeyResponse = "\"a\":\"abcd\"";
            mockServer.expect(requestTo("http://localhost:8081/test"))
                    .andExpect(method(HttpMethod.GET))
                    .andRespond(withSuccess(mockKeyResponse, MediaType.TEXT_PLAIN));

            RestTemplateBuilder builder = mock(RestTemplateBuilder.class);
            when(builder.build()).thenReturn(restTemplate);
            return builder;
        

    



以下是创建要测试的bean的示例代码。

@Configuration
public class BeanConfig 
    @Bean
    public SampleBean sampleBean()
        Resource resource = new UrlResource("");
        // Some operation using resource and create the sampleBean bean
        return sampleBean;
    

使用上述方法我得到 “ java.net.ConnectException:连接被拒绝(连接被拒绝)” 错误,因为它无法访问http://localhost:8081/test 端点。

【问题讨论】:

你正在这里构建一个新的模拟,而不是返回你构建的模拟return mock(RestTemplateBuilder.class).build(); 看起来很时髦。 @ThomasAndolf 对编辑后的代码示例感到抱歉。 【参考方案1】:

使用@InjectMocks

参考:documentation 和 Explaination with example.

【讨论】:

无法使用 @InjectMocks。我必须在 bean 初始化开始之前或在调用特定 bean 之前创建对象并准备好 url。【参考方案2】:

我通过在 testConfiguration 中创建一个 MockServiceServer 解决了这个问题。 示例代码如下。

@TestConfiguration
    static class TestConfig 

        @Bean
        public RestTemplateBuilder restTemplateBuilder() 
            RestTemplate restTemplate = new RestTemplate();
            MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
            String mockKeyResponse = "\"a\":\"abcd\"";
            mockServer.expect(requestTo("http://localhost:8081/test"))
                    .andExpect(method(HttpMethod.GET))
                    .andRespond(withSuccess(mockKeyResponse, MediaType.TEXT_PLAIN));

            RestTemplateBuilder builder = mock(RestTemplateBuilder.class);
            when(builder.build()).thenReturn(restTemplate);
            return builder;
        

    

然后在我需要使用它的类 BeanConfig 中,我使用构造函数注入自动装配,以便在创建 BeanConfig 类的 bean 之前创建 RestTemplate。 以下是我的做法。

@Configuration
public class BeanConfig 

    private RestTemplate restTemplate;

    public BeanConfig(RestTemplate restTemplate) 
        this.restTemplate = restTemplate;
    

    @Bean
    public SampleBean sampleBean()
        Resource resource = new UrlResource("");
        // Some operation using resource and create the sampleBean bean
        return sampleBean;
    

【讨论】:

以上是关于我想在 Spring Boot 集成测试中创建 bean 之前模拟服务器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中创建一个调用包含构造函数注入的服务的测试?

如何在 Spring Boot 客户端应用程序中创建不共享底层网络连接的套接字

用于集成测试的 Spring Boot @LocalServerPort 的 DotNet 替代方案

如何在 Spring Boot 中创建不同的 ThreadPoolTask​​Executor? [复制]

如何在 Spring Boot Rest api 中创建安全登录控制器

从 Spring-Boot 测试中排除 elasticsearchTemplate