0
# Web Testing
1
2
Spring Boot provides comprehensive testing support for web applications with dedicated annotations and testing utilities for controllers, web layers, and full integration testing.
3
4
## Capabilities
5
6
### @WebMvcTest Integration
7
8
Test Spring MVC controllers with focused test slicing that loads only web layer components.
9
10
```java { .api }
11
/**
12
* Web MVC test annotation for controller testing
13
*/
14
@WebMvcTest(UserController.class)
15
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
16
class UserControllerTest {
17
18
@Autowired
19
private MockMvc mockMvc;
20
21
@MockBean
22
private UserService userService;
23
24
@Test
25
void shouldGetUser() throws Exception {
26
// Test implementation
27
}
28
}
29
30
/**
31
* Web MVC test for all controllers
32
*/
33
@WebMvcTest
34
class AllControllersTest {
35
@Autowired
36
private MockMvc mockMvc;
37
}
38
```
39
40
**Usage Examples:**
41
42
```java
43
@WebMvcTest(ProductController.class)
44
class ProductControllerTest {
45
46
@Autowired
47
private MockMvc mockMvc;
48
49
@MockBean
50
private ProductService productService;
51
52
@Autowired
53
private ObjectMapper objectMapper;
54
55
@Test
56
void shouldCreateProduct() throws Exception {
57
Product product = new Product("Test Product", 29.99);
58
Product savedProduct = new Product(1L, "Test Product", 29.99);
59
60
when(productService.save(any(Product.class))).thenReturn(savedProduct);
61
62
mockMvc.perform(post("/api/products")
63
.contentType(MediaType.APPLICATION_JSON)
64
.content(objectMapper.writeValueAsString(product)))
65
.andExpect(status().isCreated())
66
.andExpect(jsonPath("$.id").value(1))
67
.andExpect(jsonPath("$.name").value("Test Product"))
68
.andExpect(jsonPath("$.price").value(29.99));
69
}
70
71
@Test
72
void shouldGetProduct() throws Exception {
73
Product product = new Product(1L, "Test Product", 29.99);
74
when(productService.findById(1L)).thenReturn(product);
75
76
mockMvc.perform(get("/api/products/1"))
77
.andExpect(status().isOk())
78
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
79
.andExpect(jsonPath("$.name").value("Test Product"));
80
}
81
82
@Test
83
void shouldReturnNotFoundForNonExistentProduct() throws Exception {
84
when(productService.findById(999L)).thenThrow(new ProductNotFoundException());
85
86
mockMvc.perform(get("/api/products/999"))
87
.andExpect(status().isNotFound());
88
}
89
}
90
```
91
92
### MockMvc Testing
93
94
Comprehensive MockMvc API for testing web layer interactions.
95
96
```java { .api }
97
/**
98
* MockMvc request builders and matchers
99
*/
100
public class MockMvcRequestBuilders {
101
public static MockHttpServletRequestBuilder get(String urlTemplate, Object... uriVars);
102
public static MockHttpServletRequestBuilder post(String urlTemplate, Object... uriVars);
103
public static MockHttpServletRequestBuilder put(String urlTemplate, Object... uriVars);
104
public static MockHttpServletRequestBuilder delete(String urlTemplate, Object... uriVars);
105
public static MockHttpServletRequestBuilder patch(String urlTemplate, Object... uriVars);
106
}
107
108
/**
109
* Request customization
110
*/
111
public interface MockHttpServletRequestBuilder {
112
MockHttpServletRequestBuilder contentType(MediaType mediaType);
113
MockHttpServletRequestBuilder content(String content);
114
MockHttpServletRequestBuilder header(String name, Object... values);
115
MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders);
116
MockHttpServletRequestBuilder param(String name, String... values);
117
MockHttpServletRequestBuilder cookie(Cookie... cookies);
118
MockHttpServletRequestBuilder sessionAttr(String name, Object value);
119
MockHttpServletRequestBuilder principal(Principal principal);
120
}
121
122
/**
123
* Response verification
124
*/
125
public class MockMvcResultMatchers {
126
public static StatusResultMatchers status();
127
public static ContentResultMatchers content();
128
public static JsonPathResultMatchers jsonPath(String expression, Object... args);
129
public static HeaderResultMatchers header();
130
public static ModelResultMatchers model();
131
public static ViewResultMatchers view();
132
public static RedirectResultMatchers redirectedUrl(String expectedUrl);
133
}
134
```
135
136
**Usage Examples:**
137
138
```java
139
@Test
140
void shouldHandleFormSubmission() throws Exception {
141
mockMvc.perform(post("/users")
142
.param("name", "John Doe")
143
.param("email", "john@example.com")
144
.contentType(MediaType.APPLICATION_FORM_URLENCODED))
145
.andExpect(status().is3xxRedirection())
146
.andExpect(redirectedUrl("/users/success"));
147
}
148
149
@Test
150
void shouldHandleFileUpload() throws Exception {
151
MockMultipartFile file = new MockMultipartFile(
152
"file", "test.txt", "text/plain", "Hello, World!".getBytes());
153
154
mockMvc.perform(multipart("/api/upload")
155
.file(file)
156
.param("description", "Test file"))
157
.andExpect(status().isOk())
158
.andExpect(content().string(containsString("File uploaded")));
159
}
160
161
@Test
162
void shouldValidateRequestBody() throws Exception {
163
Product invalidProduct = new Product("", -10.0); // Invalid data
164
165
mockMvc.perform(post("/api/products")
166
.contentType(MediaType.APPLICATION_JSON)
167
.content(objectMapper.writeValueAsString(invalidProduct)))
168
.andExpect(status().isBadRequest())
169
.andExpect(jsonPath("$.name").value("Name is required"))
170
.andExpect(jsonPath("$.price").value("Price must be positive"));
171
}
172
```
173
174
### Integration Testing
175
176
Full application context testing with @SpringBootTest and TestRestTemplate.
177
178
```java { .api }
179
/**
180
* Full integration test with embedded server
181
*/
182
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
183
class UserIntegrationTest {
184
185
@Autowired
186
private TestRestTemplate restTemplate;
187
188
@LocalServerPort
189
private int port;
190
191
@Test
192
void shouldCreateAndRetrieveUser() {
193
// Integration test implementation
194
}
195
}
196
197
/**
198
* Integration test with mock web environment
199
*/
200
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
201
@AutoConfigureTestDatabase
202
class UserRepositoryIntegrationTest {
203
204
@Autowired
205
private MockMvc mockMvc;
206
207
@Autowired
208
private UserRepository userRepository;
209
}
210
```
211
212
**Usage Examples:**
213
214
```java
215
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
216
@TestPropertySource(locations = "classpath:application-test.properties")
217
class ProductIntegrationTest {
218
219
@Autowired
220
private TestRestTemplate restTemplate;
221
222
@Autowired
223
private ProductRepository productRepository;
224
225
@LocalServerPort
226
private int port;
227
228
@Test
229
void shouldCreateProductThroughApi() {
230
Product product = new Product("Integration Test Product", 39.99);
231
232
ResponseEntity<Product> response = restTemplate.postForEntity(
233
"/api/products", product, Product.class);
234
235
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
236
assertThat(response.getBody().getId()).isNotNull();
237
assertThat(response.getBody().getName()).isEqualTo("Integration Test Product");
238
239
// Verify in database
240
Optional<Product> savedProduct = productRepository.findById(response.getBody().getId());
241
assertThat(savedProduct).isPresent();
242
}
243
244
@Test
245
void shouldGetProductList() {
246
// Seed test data
247
productRepository.save(new Product("Product 1", 10.0));
248
productRepository.save(new Product("Product 2", 20.0));
249
250
ResponseEntity<Product[]> response = restTemplate.getForEntity(
251
"/api/products", Product[].class);
252
253
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
254
assertThat(response.getBody()).hasSize(2);
255
}
256
}
257
```
258
259
### Test Security Configuration
260
261
Testing with Spring Security integration and authentication.
262
263
```java { .api }
264
/**
265
* Security testing with @WithMockUser
266
*/
267
@WebMvcTest(SecureController.class)
268
class SecureControllerTest {
269
270
@Autowired
271
private MockMvc mockMvc;
272
273
@Test
274
@WithMockUser(roles = "ADMIN")
275
void shouldAllowAdminAccess() throws Exception {
276
mockMvc.perform(get("/admin/users"))
277
.andExpect(status().isOk());
278
}
279
280
@Test
281
@WithMockUser(roles = "USER")
282
void shouldDenyUserAccess() throws Exception {
283
mockMvc.perform(get("/admin/users"))
284
.andExpect(status().isForbidden());
285
}
286
287
@Test
288
void shouldRequireAuthentication() throws Exception {
289
mockMvc.perform(get("/admin/users"))
290
.andExpect(status().isUnauthorized());
291
}
292
}
293
294
/**
295
* Custom security test user
296
*/
297
@WithMockUser(username = "testuser", roles = {"USER", "ADMIN"})
298
@Test
299
void shouldAllowCustomUser() throws Exception {
300
// Test with custom user
301
}
302
```
303
304
### Test Configuration and Profiles
305
306
Configure test-specific beans and properties.
307
308
```java { .api }
309
/**
310
* Test configuration class
311
*/
312
@TestConfiguration
313
public class TestConfig {
314
315
@Bean
316
@Primary
317
public Clock testClock() {
318
return Clock.fixed(Instant.parse("2023-01-01T00:00:00Z"), ZoneOffset.UTC);
319
}
320
321
@Bean
322
@Primary
323
public EmailService mockEmailService() {
324
return Mockito.mock(EmailService.class);
325
}
326
}
327
328
/**
329
* Import test configuration
330
*/
331
@WebMvcTest
332
@Import(TestConfig.class)
333
class ControllerWithTestConfigTest {
334
// Test with custom configuration
335
}
336
```
337
338
## Types
339
340
```java { .api }
341
// MockMvc for web layer testing
342
public class MockMvc {
343
public ResultActions perform(MockHttpServletRequestBuilder requestBuilder) throws Exception;
344
}
345
346
// Test result actions for chaining expectations
347
public interface ResultActions {
348
ResultActions andExpect(ResultMatcher matcher) throws Exception;
349
ResultActions andDo(ResultHandler handler) throws Exception;
350
MvcResult andReturn() throws Exception;
351
}
352
353
// Test RestTemplate for integration testing
354
public class TestRestTemplate {
355
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);
356
public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables);
357
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables);
358
}
359
360
// Test annotations
361
@Target(ElementType.TYPE)
362
@Retention(RetentionPolicy.RUNTIME)
363
@ExtendWith(SpringExtension.class)
364
public @interface WebMvcTest {
365
Class<?>[] value() default {};
366
Class<?>[] controllers() default {};
367
boolean useDefaultFilters() default true;
368
}
369
370
@Target({ElementType.TYPE})
371
@Retention(RetentionPolicy.RUNTIME)
372
@ExtendWith(SpringExtension.class)
373
public @interface SpringBootTest {
374
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
375
376
enum WebEnvironment {
377
MOCK, RANDOM_PORT, DEFINED_PORT, NONE
378
}
379
}
380
381
// Mock annotations
382
@Target({ElementType.FIELD, ElementType.PARAMETER})
383
@Retention(RetentionPolicy.RUNTIME)
384
public @interface MockBean {
385
}
386
387
@Target({ElementType.FIELD, ElementType.PARAMETER})
388
@Retention(RetentionPolicy.RUNTIME)
389
public @interface SpyBean {
390
}
391
392
// Security testing annotation
393
@Target({ElementType.METHOD, ElementType.TYPE})
394
@Retention(RetentionPolicy.RUNTIME)
395
public @interface WithMockUser {
396
String value() default "user";
397
String username() default "";
398
String[] roles() default {"USER"};
399
String[] authorities() default {};
400
}
401
```