mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-20 16:15:12 +00:00
- Introduced MockMvcTester for AssertJ-style assertions in Spring MVC testing. - Added @RestClientTest for testing REST clients with MockRestServiceServer. - Implemented RestTestClient as a modern alternative to TestRestTemplate. - Documented migration steps from Spring Boot 3.x to 4.0, including dependency and annotation changes. - Created an overview of test slices to guide testing strategies. - Included Testcontainers setup for JDBC testing with PostgreSQL and MySQL. - Enhanced @WebMvcTest documentation with examples for various HTTP methods and validation.
4.6 KiB
4.6 KiB
@RestClientTest
Testing REST clients in isolation with MockRestServiceServer.
Overview
@RestClientTest auto-configures:
- RestTemplate/RestClient with mock server support
- Jackson ObjectMapper
- MockRestServiceServer
Basic Setup
@RestClientTest(WeatherService.class)
class WeatherServiceTest {
@Autowired
private WeatherService weatherService;
@Autowired
private MockRestServiceServer server;
}
Testing RestTemplate
@RestClientTest(WeatherService.class)
class WeatherServiceTest {
@Autowired
private WeatherService weatherService;
@Autowired
private MockRestServiceServer server;
@Test
void shouldFetchWeather() {
// Given
server.expect(requestTo("https://api.weather.com/v1/current"))
.andExpect(method(HttpMethod.GET))
.andExpect(queryParam("city", "Berlin"))
.andRespond(withSuccess()
.contentType(MediaType.APPLICATION_JSON)
.body("{\"temperature\": 22, \"condition\": \"Sunny\"}"));
// When
Weather weather = weatherService.getCurrentWeather("Berlin");
// Then
assertThat(weather.getTemperature()).isEqualTo(22);
assertThat(weather.getCondition()).isEqualTo("Sunny");
}
}
Testing RestClient (Spring 6.1+)
@RestClientTest(WeatherService.class)
class WeatherServiceTest {
@Autowired
private WeatherService weatherService;
@Autowired
private MockRestServiceServer server;
@Test
void shouldFetchWeatherWithRestClient() {
server.expect(requestTo("https://api.weather.com/v1/current"))
.andRespond(withSuccess()
.body("{\"temperature\": 22}"));
Weather weather = weatherService.getCurrentWeather("Berlin");
assertThat(weather.getTemperature()).isEqualTo(22);
}
}
Request Matching
Exact URL
server.expect(requestTo("https://api.example.com/users/1"))
.andRespond(withSuccess());
URL Pattern
server.expect(requestTo(matchesPattern("https://api.example.com/users/\\d+")))
.andRespond(withSuccess());
HTTP Method
server.expect(ExpectedCount.once(),
requestTo("https://api.example.com/users"))
.andExpect(method(HttpMethod.POST))
.andRespond(withCreatedEntity(URI.create("/users/1")));
Request Body
server.expect(requestTo("https://api.example.com/users"))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json("{\"name\": \"John\"}"))
.andRespond(withSuccess());
Headers
server.expect(requestTo("https://api.example.com/users"))
.andExpect(header("Authorization", "Bearer token123"))
.andExpect(header("X-Api-Key", "secret"))
.andRespond(withSuccess());
Response Types
Success with Body
server.expect(requestTo("/users/1"))
.andRespond(withSuccess()
.contentType(MediaType.APPLICATION_JSON)
.body("{\"id\": 1, \"name\": \"John\"}"));
Success from Resource
server.expect(requestTo("/users/1"))
.andRespond(withSuccess()
.body(new ClassPathResource("user-response.json")));
Created
server.expect(requestTo("/users"))
.andExpect(method(HttpMethod.POST))
.andRespond(withCreatedEntity(URI.create("/users/1")));
Error Response
server.expect(requestTo("/users/999"))
.andRespond(withResourceNotFound());
server.expect(requestTo("/users"))
.andRespond(withServerError()
.body("Internal Server Error"));
server.expect(requestTo("/users"))
.andRespond(withStatus(HttpStatus.BAD_REQUEST)
.body("{\"error\": \"Invalid input\"}"));
Verifying Requests
@Test
void shouldCallApi() {
server.expect(ExpectedCount.once(),
requestTo("https://api.example.com/data"))
.andRespond(withSuccess());
service.fetchData();
server.verify(); // Verify all expectations met
}
Ignoring Extra Requests
@Test
void shouldHandleMultipleCalls() {
server.expect(ExpectedCount.manyTimes(),
requestTo(matchesPattern("/api/.*")))
.andRespond(withSuccess());
// Multiple calls allowed
service.callApi();
service.callApi();
service.callApi();
}
Reset Between Tests
@BeforeEach
void setUp() {
server.reset();
}
Testing Timeouts
server.expect(requestTo("/slow-endpoint"))
.andRespond(withSuccess()
.body("{\"data\": \"test\"}")
.delay(100, TimeUnit.MILLISECONDS));
// Test timeout handling
Best Practices
- Always verify
server.verify()at end of test - Use resource files for large JSON responses
- Match on minimal set of request attributes
- Reset server in @BeforeEach
- Test error responses, not just success
- Verify request body for POST/PUT calls