@WebMvcTest helps you test only the web layer of your Spring Boot app without starting the full application. It makes controller testing faster and focused.
@WebMvcTest for controller testing in Spring Boot
@WebMvcTest(ControllerClass.class) public class YourControllerTest { @Autowired private MockMvc mockMvc; // test methods here }
Use @WebMvcTest with the controller class you want to test.
MockMvc is used to simulate HTTP requests and check responses.
@WebMvcTest(HelloController.class) public class HelloControllerTest { @Autowired private MockMvc mockMvc; @Test public void testHello() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string("Hello World")); } }
@WebMvcTest public class MultipleControllersTest { @Autowired private MockMvc mockMvc; // Tests for multiple controllers if no specific class is given }
@WebMvcTest(UserController.class) @Import(UserService.class) // Import service if needed public class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserRepository userRepository; // Test methods }
This example tests the GreetingController's /greet endpoint. It mocks GreetingService to return "Hello Test" instead of the real value. The test checks that the controller returns the mocked string with HTTP 200 status.
package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(GreetingController.class) public class GreetingControllerTest { @Autowired private MockMvc mockMvc; @MockBean private GreetingService greetingService; @Test public void testGreeting() throws Exception { // Mock the service to return "Hello Test" org.mockito.Mockito.when(greetingService.greet()).thenReturn("Hello Test"); mockMvc.perform(get("/greet")) .andExpect(status().isOk()) .andExpect(content().string("Hello Test")); } } // Controller class package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class GreetingController { private final GreetingService greetingService; public GreetingController(GreetingService greetingService) { this.greetingService = greetingService; } @GetMapping("/greet") public String greet() { return greetingService.greet(); } } // Service class package com.example.demo; import org.springframework.stereotype.Service; @Service public class GreetingService { public String greet() { return "Hello World"; } }
@WebMvcTest loads only web-related beans, so other beans must be mocked or imported.
Use @MockBean to create mocks for dependencies your controller needs.
MockMvc lets you simulate HTTP requests without starting a server.
@WebMvcTest is for focused testing of Spring MVC controllers.
It speeds up tests by loading only web layer components.
Use MockMvc and @MockBean to test controller behavior and dependencies.
Practice
@WebMvcTest in Spring Boot testing?Solution
Step 1: Understand the role of @WebMvcTest
@WebMvcTest is designed to load only the Spring MVC components like controllers, filters, and related configurations, not the full app context.Step 2: Compare with other test annotations
Unlike @SpringBootTest which loads the full context, @WebMvcTest focuses on controller layer for fast, isolated web tests.Final Answer:
To test only the web layer (controllers) without starting the full application context -> Option AQuick Check:
@WebMvcTest = controller-only test [OK]
- Thinking @WebMvcTest loads full Spring context
- Confusing @WebMvcTest with @SpringBootTest
- Assuming it tests service or repository layers
@WebMvcTest for a controller named UserController?Solution
Step 1: Check @WebMvcTest syntax for specifying controllers
The correct syntax to specify which controllers to test is using the 'controllers' attribute, e.g., @WebMvcTest(controllers = UserController.class).Step 2: Eliminate incorrect options
@WebMvcTest(UserController.class) public class UserControllerTest {} misses 'controllers =' keyword, @WebMvcTest public class UserControllerTest {} does not specify controller, @WebMvcTest(services = UserController.class) public class UserControllerTest {} wrongly uses 'services' attribute.Final Answer:
@WebMvcTest(controllers = UserController.class) public class UserControllerTest {} -> Option DQuick Check:
@WebMvcTest(controllers = ...) is correct syntax [OK]
- Omitting 'controllers =' keyword
- Using 'services =' instead of 'controllers ='
- Not specifying any controller class
@WebMvcTest and MockMvc, what will be the HTTP status returned by the test?@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk());
}
}
@RestController
class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "Hello World";
}
}Solution
Step 1: Analyze the controller mapping
The HelloController has a GET mapping for '/hello' that returns a string "Hello World".Step 2: Understand MockMvc test behavior
The test performs a GET request to '/hello' and expects status 200 OK, which matches the controller's response.Final Answer:
200 OK -> Option BQuick Check:
GET /hello returns 200 OK [OK]
- Expecting 404 when mapping exists
- Confusing status codes for successful GET
- Missing controller in @WebMvcTest causing 404
@WebMvcTest test class that causes the test to fail with a NullPointerException.@WebMvcTest(controllers = UserController.class)
public class UserControllerTest {
private MockMvc mockMvc;
@Test
public void testGetUser() throws Exception {
mockMvc.perform(get("/user/1"))
.andExpect(status().isOk());
}
}Solution
Step 1: Check MockMvc initialization
The MockMvc field is declared but not initialized or injected, so it remains null causing NullPointerException.Step 2: Fix by adding @Autowired
Adding @Autowired on the MockMvc field lets Spring inject the mockMvc instance for testing.Final Answer:
Missing @Autowired annotation on MockMvc field -> Option AQuick Check:
MockMvc must be @Autowired to avoid null [OK]
- Forgetting @Autowired on MockMvc
- Assuming MockMvc is auto-initialized without annotation
- Misnaming test methods without @Test
OrderController that depends on a service OrderService. Using @WebMvcTest, how can you provide a mock OrderService to the controller during testing?Solution
Step 1: Understand @WebMvcTest scope
@WebMvcTest loads only web layer, so service beans are not loaded automatically.Step 2: Use @MockBean to provide mock dependencies
Annotating OrderService with @MockBean in the test class creates and injects a mock into the controller.Final Answer:
Use @MockBean on OrderService field in the test class to inject a mock -> Option CQuick Check:
@MockBean mocks service dependencies in @WebMvcTest [OK]
- Trying to @Autowired real service in @WebMvcTest
- Not mocking service causing NoSuchBeanDefinitionException
- Switching to @SpringBootTest unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
