spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.27k stars 37.99k forks source link

MockRestServiceServer.verify() did not work with single API testing if project has more than one API #28278

Closed copsafe closed 1 year ago

copsafe commented 2 years ago

Affects: 5.3.18

MockRestServiceServer.verify() did not work with single API testing if project has more than one API.

Example:

@Component
public class Test {

    @Autowired
    private RestTemplate restTemplate;

    @Scheduled(fixedDelay = 3000)
    public void schedule1() {
        restTemplate.getForEntity(URI.create("http://localhost:9090/api1"), String.class);
    }

    @Scheduled(fixedDelay = 3000)
    public void schedule2() {
        restTemplate.getForEntity(URI.create("http://localhost:9090/api2"), String.class);
    }
}
@ExtendWith({ SpringExtension.class })
@SpringBootTest(classes = Demo1Application.class)
class TestTest {

    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;

    @Test
    void testSchedule1() {
        mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
        mockServer
                .expect(ExpectedCount.manyTimes(),
                        MockRestRequestMatchers.requestTo(new StringStartsWith("http://localhost:9090/api1")))
                .andExpect(MockRestRequestMatchers.method(HttpMethod.GET))
                .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK).body(""));

        mockServer.verify(Duration.ofSeconds(10));
    }

    @Test
    void testSchedule2() {
        mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
        mockServer
                .expect(ExpectedCount.manyTimes(),
                        MockRestRequestMatchers.requestTo(new StringStartsWith("http://localhost:9090/api2")))
                .andExpect(MockRestRequestMatchers.method(HttpMethod.GET))
                .andRespond(MockRestResponseCreators.withStatus(HttpStatus.OK).body(""));
        mockServer.verify(Duration.ofSeconds(10));
    }

}

If the schedule1 executes first, then the testSchedule2 fails and vice versa.

java.lang.AssertionError: No further requests expected: HTTP GET http://localhost:9090/api1
0 request(s) executed.

The Map requestFailures in AbstractRequestExpectationManager seems stores all executed APIs even it is not expected.

rstoyanchev commented 1 year ago

When the RestTempate instance is bound to MockRestServiceServer, it needs to be configured with mock responses for all expected requests, or otherwise there is no way to know otherwise what response to send. Note that we recently added a feature in #29721 that allows some requests to be executed by actually making an HTTP call rather than returning a mock response. In case that was your expectation.

In any case, this is expected behavior, so I'm closing the issue, but feel free to comment further.