java 由于未绑定 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39070654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:03:58  来源:igfitidea点击:

Spring-Boot RestClientTest not correctly auto-configuring MockRestServiceServer due to unbound RestTemplate

javaspringrestspring-boot

提问by Josh C

EDIT: This question is specifically pertaining to the @RestClientTest annotation introduced in spring-boot 1.4.0 which is intended to replace the factory method.

编辑:这个问题特别与 spring-boot 1.4.0 中引入的 @RestClientTest 注释有关,该注释旨在替换工厂方法。

Problem:

问题:

According to the documentationthe @RestClientTest should correctly configure a MockRestServiceServer to use when testing a REST client. However when running a test I am getting an IllegalStateException saying the MockServerRestTemplateCustomizer has not been bound to a RestTemplate.

根据文档,@RestClientTest 应该正确配置 MockRestServiceServer 以在测试 REST 客户端时使用。但是,在运行测试时,我收到一个 IllegalStateException,说 MockServerRestTemplateCustomizer 尚未绑定到 RestTemplate。

Its worth noting that I'm using Gson for deserialization and not Hymanson, hence the exclude.

值得注意的是,我使用 Gson 进行反序列化而不是 Hymanson,因此排除在外。

Does anyone know how to correctly use this new annotation? I haven't found any examples that require more configuration then when I have already.

有谁知道如何正确使用这个新注释?我还没有找到任何需要更多配置的示例。

Configuration:

配置:

@SpringBootConfiguration
@ComponentScan
@EnableAutoConfiguration(exclude = {HymansonAutoConfiguration.class})
public class ClientConfiguration {

...

   @Bean
   public RestTemplateBuilder restTemplateBuilder() {
       return new RestTemplateBuilder()
            .rootUri(rootUri)
            .basicAuthorization(username, password);
   }
}

Client:

客户:

@Service
public class ComponentsClientImpl implements ComponentsClient {

    private RestTemplate restTemplate;

    @Autowired
    public ComponentsClientImpl(RestTemplateBuilder builder) {
        this.restTemplate = builder.build();
    }

    public ResponseDTO getComponentDetails(RequestDTO requestDTO) {
        HttpEntity<RequestDTO> entity = new HttpEntity<>(requestDTO);
        ResponseEntity<ResponseDTO> response = 
              restTemplate.postForEntity("/api", entity, ResponseDTO.class);
        return response.getBody();
    }
}

Test

测试

@RunWith(SpringRunner.class)
@RestClientTest(ComponentsClientImpl.class)
public class ComponentsClientTest {

    @Autowired
    private ComponentsClient client;

    @Autowired
    private MockRestServiceServer server;

    @Test
    public void getComponentDetailsWhenResultIsSuccessShouldReturnComponentDetails() throws Exception {
        server.expect(requestTo("/api"))
            .andRespond(withSuccess(getResponseJson(), APPLICATION_JSON));

        ResponseDTO response = client.getComponentDetails(requestDto);
        ResponseDTO expected = responseFromJson(getResponseJson());

        assertThat(response, is(expectedResponse));
    }
}

And the Exception:

和例外:

java.lang.IllegalStateException: Unable to use auto-configured MockRestServiceServer since MockServerRestTemplateCustomizer has not been bound to a RestTemplate

Answer:

回答:

As per the answer below there is no need to declare a RestTemplateBuilder bean into the context as it is already provided by the spring-boot auto-configuration.

根据下面的答案,不需要在上下文中声明 RestTemplateBuilder bean,因为它已经由 spring-boot 自动配置提供。

If the project is a spring-boot application (it has @SpringBootApplication annotation) this will work as intended. In the above case however the project was a client-library and thus had no main application.

如果项目是一个 spring-boot 应用程序(它有 @SpringBootApplication 注释),这将按预期工作。然而,在上述情况下,该项目是一个客户端库,因此没有主要应用程序。

In order to ensure the RestTemplateBuilder was injected correctly in the main application context (the bean having been removed) the component scan needs a CUSTOM filter (the one used by @SpringBootApplication)

为了确保在主应用程序上下文中正确注入 RestTemplateBuilder(bean 已被删除),组件扫描需要一个 CUSTOM 过滤器(@SpringBootApplication 使用的过滤器)

@ComponentScan(excludeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)
})

采纳答案by abaghel

You have RestTemplateBuilder at two places. At ClientConfiguration class and at ComponentsClientImpl class. Spring boot 1.4.0 auto-configure a RestTemplateBuilder which can be used to create RestTemplate instances when needed. Remove below code from ClientConfiguration class and run your test.

您在两个地方都有 RestTemplateBuilder。在 ClientConfiguration 类和 ComponentsClientImpl 类中。Spring boot 1.4.0 自动配置了一个 RestTemplateBuilder,可用于在需要时创建 RestTemplate 实例。从 ClientConfiguration 类中删除以下代码并运行您的测试。

 @Bean
 public RestTemplateBuilder restTemplateBuilder() {
   return new RestTemplateBuilder()
        .rootUri(rootUri)
        .basicAuthorization(username, password);
  }

回答by Deroude

The MockRestServiceServerinstance should be constructed from the static factory, using a RestTemplate. See thisarticle for a detailed description of the testing process.

MockRestServiceServer实例应该从静态工厂构造,使用RestTemplate. 请参见文章对测试过程的详细描述。

In your example, you can do:

在您的示例中,您可以执行以下操作:

@RunWith(SpringRunner.class)
@RestClientTest(ComponentsClientImpl.class)
public class ComponentsClientTest {

    @Autowired
    private ComponentsClient client;

    @Autowired
    private RestTemplate template;

    private MockRestServiceServer server;

    @Before
    public void setUp() {
        server= MockRestServiceServer.createServer(restTemplate);
    }

    /*Do your test*/
}