【问题标题】:Can we use @RestClientTest when the rest template has interceptors using Spring boot 1.5.x?当rest模板有使用Spring boot 1.5.x的拦截器时,我们可以使用@RestClientTest吗?
【发布时间】:2020-07-17 05:14:19
【问题描述】:

我使用的是 Spring Boot 1.5.x (Spring 4.2.x),我创建了一个 RestClientSdk spring 组件类,如下所示:

@Component
public class RestClientSdkImpl implements RestClientSdk {

    private RestTemplate restTemplate;

    @Autowired
    public RestClientSdkImpl(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }
    ...
    //other methods kept out for brevity
}

我还定义了一个 DefaultRestTemplateCustomizer 弹簧组件,如下所示:

@Component
public class DefaultRestTemplateCustomizer implements RestTemplateCustomizer {

    private LogClientHttpRequestInterceptor logClientHttpRequestInterceptor;

    @Autowired
    public DefaultRestTemplateCustomizer(LogClientHttpRequestInterceptor logClientHttpRequestInterceptor) {
        this.logClientHttpRequestInterceptor = logClientHttpRequestInterceptor;
    }

    @Override
    public void customize(RestTemplate restTemplate) {
        restTemplate.getInterceptors().add(logClientHttpRequestInterceptor);
        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
    }

}

这样,我定义了一个如下所示的测试类,它使用如下所示的@RestClientTest 注解。

@RunWith(SpringRunner.class)
@RestClientTest(RestClientSdk.class)
@ActiveProfiles("test")
/*
 * The RestClientTest only includes the most minimal configuration to include a rest template builder, 
 * so we include the rest sdk auto config within the scope of the test 
 */ 
@ImportAutoConfiguration(RestSdkAutoConfiguration.class)
public class RestClientApplicationBehaviourTest{

    @Autowired
    private RestClientSdk restClientSdk;

    @Autowired
    private MockRestServiceServer mockRestServiceServer;

    /**
     * A simple Http Get that retrieves a JSON document from a rest server and 
     * produces a plain old java object as a response.
     */ 
    @Test
    public void testPlainHttpGet() throws IOException{
        //ARRANGE
        RestClientDto<?> simpleGetRequest = simpleHttpGet();
        mockRestServiceServer.expect(once(), requestTo("http://localhost:8080/account/1234567890"))
                                   .andRespond(withSuccess(IOUtils.getInputAsString("/stubs/account.json"),MediaType.APPLICATION_JSON));
        //ACT
        Account account = restClientSdk.send(simpleGetRequest, Account.class);
        //ASSERT
        mockRestServiceServer.verify();     
        Assert.assertNotNull(account);
        Assert.assertNotNull(account.getAccountId());
        Assert.assertNotNull(account.getFirstName());
        Assert.assertNotNull(account.getLastName());
    }
...
//not including other methods for brevity 
}

问题


因为 MockRestServiceServer 构建器使用 MockClientHttpRequestFactory 覆盖了我的休息模板中的 BufferingClientHttpRequestFactory,所以我从我的正文中得到一个空响应。这是因为日志拦截器正在读取来自响应的输入流,因此该流不再具有要读取的内容。 BufferingClientHttpRequestFactory 会阻止这种情况发生。现在,我知道从 Spring 5.0.5 开始,MockRestServiceServer 构建器中有一个名为 bufferContent 的额外选项,但我没有选择迁移到 Spring 5.x(Spring Boot 2 .x),所以我想知道是否有办法使用 Spring Boot 1.5.x / Spring 4.2.x 进行配置。

提前谢谢你!

胡安

【问题讨论】:

    标签: java spring spring-boot spring-mvc spring-rest


    【解决方案1】:

    为了解决这个问题,我需要定义一个测试配置,这将允许我覆盖客户端请求工厂。请看下面的代码。这有点 hacky,但我想这里真正的解决方案是升级到 Spring 5.x / Spring Boot 2.x。

    @Configuration
    @Profile("test")
    public class MockRestServiceServerConfiguration {
    
        /**
         * Wrap the Mock Rest client factory in the buffered one.  
         * @param restClientSdk The rest client SDK containing the rest template to use.
         * @return The mock rest service server to use.
         */
        @Bean
        public MockRestServiceServer mockRestServiceServer(RestClientSdkImpl restClientSdkImpl) {
            RestTemplate restTemplate = restClientSdkImpl.getRestTemplate();
            MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);
    
            //need to do this because getRequestFactory returns InterceptingHttpRequestFactory wraping the mock rest service server request factory
            List<ClientHttpRequestInterceptor> templateInterceptors = restTemplate.getInterceptors();
            restTemplate.setInterceptors(null);
    
            //now we wrap the delegate, which should be the mock rest service server request factory 
            BufferingClientHttpRequestFactory bufferingFact = new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory());
            restTemplate.setRequestFactory(bufferingFact);
            restTemplate.setInterceptors(templateInterceptors);
            return server;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-01-14
      • 1970-01-01
      • 1970-01-01
      • 2017-11-28
      • 2018-08-09
      • 1970-01-01
      • 2018-08-15
      • 2019-07-07
      • 2016-06-17
      相关资源
      最近更新 更多