由于未绑定的 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer
Posted
技术标签:
【中文标题】由于未绑定的 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer【英文标题】:Spring-Boot RestClientTest not correctly auto-configuring MockRestServiceServer due to unbound RestTemplate 【发布时间】:2016-12-28 11:32:23 【问题描述】:编辑:这个问题专门与 spring-boot 1.4.0 中引入的 @RestClientTest 注释有关,该注释旨在替换工厂方法。
问题:
根据documentation,@RestClientTest 应正确配置 MockRestServiceServer 以在测试 REST 客户端时使用。但是,在运行测试时,我收到 IllegalStateException,说 MockServerRestTemplateCustomizer 尚未绑定到 RestTemplate。
值得注意的是,我使用 Gson 进行反序列化,而不是 Jackson,因此排除。
有人知道如何正确使用这个新注释吗?我还没有找到任何需要更多配置的示例。
配置:
@SpringBootConfiguration
@ComponentScan
@EnableAutoConfiguration(exclude = JacksonAutoConfiguration.class)
public class ClientConfiguration
...
@Bean
public RestTemplateBuilder restTemplateBuilder()
return new RestTemplateBuilder()
.rootUri(rootUri)
.basicAuthorization(username, password);
客户:
@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();
测试
@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));
还有例外:
java.lang.IllegalStateException: Unable to use auto-configured MockRestServiceServer since MockServerRestTemplateCustomizer has not been bound to a RestTemplate
答案:
根据下面的答案,不需要将 RestTemplateBuilder bean 声明到上下文中,因为它已经由 spring-boot 自动配置提供。
如果项目是一个 spring-boot 应用程序(它有 @SpringBootApplication 注解),这将按预期工作。然而,在上述情况下,该项目是一个客户端库,因此没有主应用程序。
为了确保在主应用程序上下文中正确注入 RestTemplateBuilder(bean 已被删除),组件扫描需要一个自定义过滤器(@SpringBootApplication 使用的过滤器)
@ComponentScan(excludeFilters =
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)
)
【问题讨论】:
【参考方案1】:您在两个地方都有 RestTemplateBuilder。在 ClientConfiguration 类和 ComponentsClientImpl 类中。 Spring boot 1.4.0 自动配置一个 RestTemplateBuilder ,可用于在需要时创建 RestTemplate 实例。从 ClientConfiguration 类中删除以下代码并运行您的测试。
@Bean
public RestTemplateBuilder restTemplateBuilder()
return new RestTemplateBuilder()
.rootUri(rootUri)
.basicAuthorization(username, password);
【讨论】:
您能否进一步详细说明您的意思?如果我删除了 bean 实例化,当在具有常规 spring 上下文(即常规 @SpringBootTest)的代码中使用时,RestTemplateBuilder 是如何注入的?此更改现在通过了我的 @RestClientTest 但其他所有操作都失败了,因为上下文中没有 bean。 在 Spring Boot 1.4.0 应用程序 RestTemplateBuilder 可作为 bean 使用,您可以简单地使用它。 所以这里的关键似乎是 @SpringBootApplication 注释,它提供了您所说的 RestTemplateBuilder 。我的项目中没有这个,因为我正在编写一个客户端库,它的独立测试上下文中没有应用程序上下文。我必须手动为需要它的测试添加它,而 RestClientTest 提供了它。您能否将此详细信息添加到您的答案中,以便为其他人澄清。 “两个地方的构建器”注释非常令人困惑 - 因为它实际上不在两个地方,而是由自动配置提供的。 @abaghel 有没有办法使用配置中的 RestTemplateBuilder 条目来完成这项工作?我需要能够设置全局 RestTemplateBuilder 错误处理程序【参考方案2】:MockRestServiceServer
实例应使用RestTemplate
从静态工厂构造。测试过程的详细描述见this文章。
在你的例子中,你可以这样做:
@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*/
【讨论】:
这种实例化方法是在 spring-boot 1.4.0 中引入的测试增强功能之前使用的。引入 @RestClientTest 是为了取消该特定的工厂方法。 docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/…以上是关于由于未绑定的 RestTemplate,Spring-Boot RestClientTest 无法正确自动配置 MockRestServiceServer的主要内容,如果未能解决你的问题,请参考以下文章
为啥 RestTemplate 不将响应表示绑定到 PagedResources?
使用resttemplate访问时,如何使端点仅接受springboot中启用@crossorigin的uri?为啥我没有收到 cors 错误? [复制]