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.
3.6 KiB
3.6 KiB
@WebMvcTest
Testing Spring MVC controllers with focused slice tests.
Basic Structure
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired
private MockMvcTester mvc;
@MockitoBean
private OrderService orderService;
@MockitoBean
private UserService userService;
}
What Gets Loaded
- The specified controller(s)
- Spring MVC infrastructure (HandlerMapping, HandlerAdapter)
- Jackson ObjectMapper (for JSON)
- Exception handlers (@ControllerAdvice)
- Spring Security filters (if on classpath)
- Validation (if on classpath)
Testing GET Endpoints
@Test
void shouldReturnOrder() {
var order = new Order(1L, "PENDING", BigDecimal.valueOf(99.99));
given(orderService.findById(1L)).willReturn(order);
assertThat(mvc.get().uri("/orders/1"))
.hasStatusOk()
.hasContentType(MediaType.APPLICATION_JSON)
.bodyJson()
.extractingPath("$.status")
.isEqualTo("PENDING");
}
Testing POST with Request Body
Using Text Blocks (Java 25)
@Test
void shouldCreateOrder() {
given(orderService.create(any(OrderRequest.class))).willReturn(1L);
var json = """
{
"product": "Product A",
"quantity": 2
}
""";
assertThat(mvc.post().uri("/orders")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.hasStatus(HttpStatus.CREATED)
.hasHeader("Location", "/orders/1");
}
Using Records
record OrderRequest(String product, int quantity) {}
@Test
void shouldCreateOrderWithRecord() {
var request = new OrderRequest("Product A", 2);
given(orderService.create(any())).willReturn(1L);
assertThat(mvc.post().uri("/orders")
.contentType(MediaType.APPLICATION_JSON)
.content(json.write(request).getJson()))
.hasStatus(HttpStatus.CREATED);
}
Testing Validation Errors
@Test
void shouldRejectInvalidOrder() {
var invalidJson = """
{
"product": "",
"quantity": -1
}
""";
assertThat(mvc.post().uri("/orders")
.contentType(MediaType.APPLICATION_JSON)
.content(invalidJson))
.hasStatus(HttpStatus.BAD_REQUEST)
.bodyJson()
.hasPath("$.errors");
}
Testing Query Parameters
@Test
void shouldFilterOrdersByStatus() {
assertThat(mvc.get().uri("/orders?status=PENDING"))
.hasStatusOk();
verify(orderService).findByStatus(OrderStatus.PENDING);
}
Testing Path Variables
@Test
void shouldCancelOrder() {
assertThat(mvc.put().uri("/orders/123/cancel"))
.hasStatusOk();
verify(orderService).cancel(123L);
}
Testing with Security
@Test
@WithMockUser(roles = "ADMIN")
void adminShouldDeleteOrder() {
assertThat(mvc.delete().uri("/orders/1"))
.hasStatus(HttpStatus.NO_CONTENT);
}
@Test
void anonymousUserShouldBeForbidden() {
assertThat(mvc.delete().uri("/orders/1"))
.hasStatus(HttpStatus.UNAUTHORIZED);
}
Multiple Controllers
@WebMvcTest({OrderController.class, ProductController.class})
class WebLayerTest {
// Tests multiple controllers in one slice
}
Excluding Auto-Configuration
@WebMvcTest(OrderController.class)
@AutoConfigureMockMvc(addFilters = false) // Skip security filters
class OrderControllerWithoutSecurityTest {
// Tests without security filters
}
Key Points
- Always mock services with @MockitoBean
- Use MockMvcTester for AssertJ-style assertions
- Test HTTP semantics (status, headers, content-type)
- Verify service method calls when side effects matter
- Don't test business logic here - that's for unit tests
- Leverage Java 25 text blocks for JSON payloads