[FIXED] Why mockServer.verify is needed in MockRestServiceServer

Issue

When using MockRestServiceServer with andExpect to test

mockServer.expect(requestTo("/hotels/42")).andExpect(method(HttpMethod.GET))
    .andRespond(withSuccess("{ \"id\" : \"42\", \"name\" : \"Holiday Inn\"}", MediaType.APPLICATION_JSON));

Then test failed if found unexpected behavior,

For example no further requests expected: HTTP if sent to unexpected URL

My Config:

@SpringBootApplication(scanBasePackages = { "..." })
public class MyConfig extends SpringBootServletInitializer {

My Test class

@ContextConfiguration( classes = {MyConfig.class})
@ActiveProfiles("local")
@WebAppConfiguration
public class My Test extends AbstractTestNGSpringContextTests {
@Autowired
@InjectMocks
private ServiceUnderMock serviceUnderMock;
private AutoCloseable closeable;

@BeforeClass
public void initMocks() {       
    closeable = MockitoAnnotations.openMocks(this);
    mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
}

@AfterClass
public void releaseMocks() throws Exception {
    closeable.close();
}

@Autowired
private RestTemplate restTemplate;

private MockRestServiceServer mockServer;
@Test
public void test() {
    try {
        mockServer.expect(ExpectedCount.min(1), 
          requestTo(new URI("https://www.google.com")))
          .andExpect(method(HttpMethod.GET));
    } catch (URISyntaxException e) {
        Assert.fail("failed to create mock");
    }    
    serviceUnderMock.doSomething();   
}

So why we need to add the mockServer.verify()?

At the end of the test use verify() to ensure all expected requests were actually performed.

Solution

The idea of MockRestServiceServer is that it allows you mock the external server such that the RestTemplate does not really need to send the requests to the actual server during the testing. Instead it just sends the requests to this MockRestServiceServer (think that it is a kind of in-memory server) and it will return the configured mocked responses for the corresponding requests.

You have to configure all the expected requests that the MockRestServiceServer will received and its corresponding responds before the test.

So basically there are two things needed to be verified which are :

  1. For every request sent by RestTemplate , there should be a mocked response configured for that request in the MockRestServiceServer

  2. For all the requests that are to be expected to be received on the MockRestServiceServer , the RestTemplate should really send out all of these expected requests.

(1) will be verified automatically whenever the RestTemplate send out a request. The exception no further requests expected: HTTP that you mentioned is because it fails (1) (i.e. forget to stub this request in the MockRestServiceServer)

(2) will not be verified automatically . You have to call MockRestServiceServer.verify() manually in order to verify it.

An example :

mockServer.expect(requestTo(new URI("https://www.yahoo.com")))
                .andExpect(method(HttpMethod.GET)).andRespond(withSuccess());
        
mockServer.expect(requestTo(new URI("https://www.google.com")))
                .andExpect(method(HttpMethod.GET)).andRespond(withSuccess());
        
        
mockServer.expect(requestTo(new URI("https://www.stackoverflow.com")))
                .andExpect(method(HttpMethod.GET)).andRespond(withSuccess());

restTemplate.getForEntity("https://www.yahoo.com", String.class);
restTemplate.getForEntity("https://www.google.com", String.class);

Without mockServer.verify() , the test still passes although RestTemplate does not send the request to https://www.stackoverflow.com which the MockServer is expected to be received.

But with mockServer.verify() , it can check that and hence fails the test.

Answered By – Ken Chan

Answer Checked By – David Marino (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published