kosker
kosker

Reputation: 333

MockRestServiceServer does not verify request properly

I'm trying to write an integration test for my spring-integration flow. I wanted to use MockRestServiceServer to record and match the outgoing requests(using http:outbound-gateway) to the Rest server. However when I call verify method of the mockServer, it's not verifying as it is expected.

I'm writing my tests in the following way:

RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);

mockServer.expect(requestTo("adfasfadf.com")).andExpect(method(HttpMethod.GET));

// Call spring integration flow here

mockServer.verify();

When I check the verify method of MockRestServiceServer, it's not calling match methods of RequestMatchers, which I believe there is something wrong with this logic. Am I missing something here?

/**
 * Verify that all expected requests set up via
 * {@link #expect(RequestMatcher)} were indeed performed.
 * @throws AssertionError when some expectations were not met
 */
public void verify() {
    if (this.expectedRequests.isEmpty() || this.expectedRequests.equals(this.actualRequests)) {
        return;
    }
    throw new AssertionError(getVerifyMessage());
}

Upvotes: 5

Views: 10014

Answers (3)

Wolf
Wolf

Reputation: 912

I think your problem is, that you don't create a response with the mockserver. I had a similar issue and this was the solution (using andRespond() is the crucial part):

mockServer.expect(requestTo("adfasfadf.com"))
    .andExpect(method(HttpMethod.GET))
    .andRespond(withSuccess());

Upvotes: 1

Artem Bilan
Artem Bilan

Reputation: 121272

I haven't used MockRestServiceServer before, but looks like this is great feature. Thank you for pointing that out!

Anyway, according to its source code we have:

public static MockRestServiceServer createServer(RestTemplate restTemplate) {
        Assert.notNull(restTemplate, "'restTemplate' must not be null");
        MockRestServiceServer mockServer = new MockRestServiceServer();
        RequestMatcherClientHttpRequestFactory factory = mockServer.new RequestMatcherClientHttpRequestFactory();
        restTemplate.setRequestFactory(factory);
        return mockServer;
    }

Pay attention, please, to the RequestMatcherClientHttpRequestFactory.

So, your RequestMatchers can be invoked only if you use that modified RestTemplate.

Hence you have to inject it to your <int-http:outbound-gateway>. Or even better share the RestTemplate instance between that gateway and this MockRestServiceServer.

Upvotes: 0

kosker
kosker

Reputation: 333

After hours of debugging, I've realised that MockRestServiceServer runs matchers during execution of the request. So, if you have an exception handler surrounding the request execution, your assertions never going to be asserted properly. This code is from RequestMatcherClientHttpRequest that runs matchers.

@Override
public ClientHttpResponse executeInternal() throws IOException {
    if (this.requestMatchers.isEmpty()) {
        throw new AssertionError("No request expectations to execute");
    }
    if (this.responseCreator == null) {
        throw new AssertionError("No ResponseCreator was set up. Add it after request expectations, "
                + "e.g. MockRestServiceServer.expect(requestTo(\"/foo\")).andRespond(withSuccess())");
    }
    for (RequestMatcher requestMatcher : this.requestMatchers) {
        requestMatcher.match(this);
    }
    setResponse(this.responseCreator.createResponse(this));

    return super.executeInternal();
}

I think this should be considered as a bug, since I believe that assertions must be executed after application execution.

Upvotes: 3

Related Questions