Можем ли мы использовать @RestClientTest, когда в шаблоне rest есть перехватчики, использующие Spring boot 1.5.x? - PullRequest
0 голосов
/ 05 апреля 2020

Я использую Spring Boot 1.5.x (Spring 4.2.x), и я создал класс компонента Spring RestClientSdk, как показано здесь:

@Component
public class RestClientSdkImpl implements RestClientSdk {

    private RestTemplate restTemplate;

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

Я также определил компонент Spring 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 переопределяет BufferingClientHttpRequestFactory в моем шаблоне отдыха с помощью MockClientHttpRequestFactory, я получаю нулевой ответ от моего тела. Это связано с тем, что перехватчик журналирования читает входной поток, поступающий из ответа, и поэтому поток больше не имеет содержимого для чтения. BufferingClientHttpRequestFactory предотвратит это. Теперь я знаю, что в Spring 5.0.5 в конструкторе MockRestServiceServer есть дополнительная опция, называемая bufferContent , но у меня нет возможности перейти в Spring 5.x (Spring Boot 2. x), поэтому мне было интересно, есть ли способ настроить это с помощью Spring Boot 1.5.x / Spring 4.2.x.

Заранее благодарю!

Juan

1 Ответ

0 голосов
/ 09 апреля 2020

Чтобы обойти эту проблему, мне нужно было определить тестовую конфигурацию, которая позволила бы мне переопределить фабрику клиентских запросов. Пожалуйста, смотрите код ниже. Это немного странно, но я полагаю, что реальным решением здесь было бы обновить версию до 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;
    }
}
...