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 :
For every request sent by
RestTemplate
, there should be a mocked response configured for that request in theMockRestServiceServer
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 - Willingham (JavaFixing Volunteer)