복붙노트

[SPRING] 동일한 URI에 대한 다중 요청을 처리하는 Spring MockRestServiceServer (자동 발견)

SPRING

동일한 URI에 대한 다중 요청을 처리하는 Spring MockRestServiceServer (자동 발견)

REST 서비스 A에 대한 Spring 통합 테스트를 작성한다고 가정 해 보겠습니다.이 서비스는 다른 REST 서비스 B를 히트하고 REST 서비스 C에서 히트 할 URI 목록을 가져옵니다. 이는 자동 발견 패턴의 일종입니다. MockRestServiceServer를 사용하여 B와 C 응답을 모의하고 싶습니다. 이제 B의 응답은 URI의 목록입니다. 모두 매우 비슷합니다. 예를 들어 B의 응답은 다음과 같습니다.

{
    uris: ["/stuff/1.json", "/stuff/2.json", "/stuff/39.json", "/stuff/47.json"]
}

단순히 서비스 A는 서비스 C의 기본 URL에 각 서비스를 추가하고 이러한 요청을합니다. 조롱 B는 단지 1 요청이기 때문에 쉽습니다. Mocking C는 모든 단일 URI를 적절한 모의 응답으로 모의해야하므로 번거로 웠습니다. 나는 그것을 자동화하고 싶다! 먼저 전체 URL이 아닌 일치하는 자체 일치자를 작성합니다.

public class RequestContainsUriMatcher implements RequestMatcher {
    private final String uri;

    public RequestContainsUriMatcher(String uri){
        this.uri = uri;
    }

    @Override
    public void match(ClientHttpRequest clientHttpRequest) throws IOException, AssertionError {
        assertTrue(clientHttpRequest.getURI().contains(uri));
    }
}

이것은 지금 내가 할 수있는 것처럼 잘 작동한다.

public RequestMatcher requestContainsUri(String uri) {
    return new RequestContainsUriMatcher(uri);
}

MockRestServiceServer.createServer(restTemplate)
            .expect(requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))
            .andRespond(/* I will get to response creator */);

이제 전체 요청 URL을 알고 모의 데이터가있는 응답 작성자 만 있으면됩니다 (테스트 리소스 폴더에 json 파일로 저장합니다).

public class AutoDiscoveryCannedDataResponseCreator implements ResponseCreator {
    private final Function<String, String> cannedDataBuilder;

    public AutoDiscoveryCannedDataResponseCreator(Function<String, String> cannedDataBuilder) {
        this.cannedDataBuilder = cannedDataBuilder;
    }

    @Override
    public ClientHttpResponse createResponse(ClientHttpRequest clientHttpRequest) throws IOException {
        return withSuccess(cannedDataBuilder.apply(requestUri), MediaType.APPLICATION_JSON)
                    .createResponse(clientHttpRequest);
    }
}

이제는 쉽고, 요청 URI를 문자열로 취해 mock 데이터를 String으로 반환하는 빌더를 작성해야합니다. 훌륭한!

public ResponseCreator withAutoDetectedCannedData() {
    Function<String, String> cannedDataBuilder = new Function<String, String>() {
        @Override
        public String apply(String requestUri) {
            //logic to get the canned data based on URI
            return cannedData;
        }
    };

    return new AutoDiscoveryCannedDataResponseCreator(cannedDataBuilder);
}

MockRestServiceServer.createServer(restTemplate)
            .expect(requestContainsUri("/stuff"))
            .andExpect(method(HttpMethod.GET))
            .andRespond(withAutoDetectedCannedData());

그것은 잘 작동합니다! .... 첫 번째 요청. 첫 번째 요청 (/stuff/1.json) 후 MockRestServiceServer는 "어설 션 오류 : 더 이상의 요청이 없습니다"라는 메시지로 응답합니다. 기본적으로, 나는 MockRestServiceServer에 .expect () 호출만큼 많은 요청을 할 수있다. 그리고 그 중 단 하나만 가지고 있기 때문에 첫 번째 요청 만 통과하게됩니다. 주위에 방법이 있습니까? 나는 10 번이나 20 번 서비스를 조롱하고 싶지 않다.

해결법

  1. ==============================

    1.MockRestServiceServer 클래스를 살펴보면 두 개의 'expect ()'메소드를 지원한다. 첫 번째 기본값은 'ExpectedCount.once ()'이지만 두 번째 방법을 사용하면이 값을 변경할 수 있습니다.

    MockRestServiceServer 클래스를 살펴보면 두 개의 'expect ()'메소드를 지원한다. 첫 번째 기본값은 'ExpectedCount.once ()'이지만 두 번째 방법을 사용하면이 값을 변경할 수 있습니다.

    public ResponseActions expect(RequestMatcher matcher) {
        return this.expect(ExpectedCount.once(), matcher);
    }
    
    public ResponseActions expect(ExpectedCount count, RequestMatcher matcher) {
        return this.expectationManager.expectRequest(count, matcher);
    }
    

    나는이 티켓 MockRestServiceServer가 두 번째 방법에 대한 몇 가지 옵션을 설명하는 여러 번 발생할 예상을 허용해야한다는 것을 알았습니다.

    귀하의 경우에는 static import를 추가하고 manyTimes () 메서드를 사용하는 것이 for 루프보다 청결한 코드라고 생각합니다.

    MockRestServiceServer
                .expect(manyTimes(), requestContainsUri("/stuff"))
                .andExpect(method(HttpMethod.GET))
    

    다른 옵션은 다음과 같습니다.

    once();
    manyTimes();
    times(5);
    min(2);
    max(8);
    between(3,6);
    
  2. ==============================

    2.편집 : 봄 4.3 이상 사용자에게 올바른 해결책을 보여주는 @emeraldjava의 답을 참조하십시오.

    편집 : 봄 4.3 이상 사용자에게 올바른 해결책을 보여주는 @emeraldjava의 답을 참조하십시오.

    불행히도 여러 호출을 기대하는 좋은 메커니즘이 없습니다. 수동으로하거나 루프를 사용합니다 (예 :

    for (int i = 0; i < 10; i++) {           
            mockRestServiceServer
                    .expect(requestContainsUri("/stuff"))
                    .andExpect(method(HttpMethod.GET))
                    .andRespond(withAutoDetectedCannedData());
    }
    

    요청은 중단없이 호출되어야한다는 점을 알아 두십시오. "/ stuff"URI와 일치하지 않는 다른 REST 호출은있을 수 없습니다.

  3. from https://stackoverflow.com/questions/30713734/spring-mockrestserviceserver-handling-multiple-requests-to-the-same-uri-auto-di by cc-by-sa and MIT license