How to Test Controller in Spring Boot: Simple Guide
To test a controller in Spring Boot, use
@WebMvcTest to load only the web layer and MockMvc to simulate HTTP requests. This approach isolates the controller and verifies its behavior without starting the full application.Syntax
Use @WebMvcTest(ControllerClass.class) to load only the controller layer for testing. Inject MockMvc to perform HTTP requests and verify responses. Use mockMvc.perform() with request builders like get() or post() and assertions like andExpect() to check status and content.
java
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.beans.factory.annotation.Autowired; 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.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @WebMvcTest(MyController.class) public class MyControllerTest { @Autowired private MockMvc mockMvc; // Example test method @org.junit.jupiter.api.Test public void testGet() throws Exception { mockMvc.perform(get("/endpoint")) .andExpect(status().isOk()) .andExpect(content().string("expected response")); } }
Example
This example shows a simple Spring Boot controller test using @WebMvcTest and MockMvc. It tests a GET request to /hello and expects a 200 OK status with the response body "Hello, Spring Boot!".
java
package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String sayHello() { return "Hello, Spring Boot!"; } } // Test class 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.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @WebMvcTest(HelloController.class) public class HelloControllerTest { @Autowired private MockMvc mockMvc; @Test public void testSayHello() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string("Hello, Spring Boot!")); } }
Output
Test passed: GET /hello returns 200 OK with "Hello, Spring Boot!"
Common Pitfalls
- Not using
@WebMvcTestcauses the entire Spring context to load, making tests slower and less focused. - Forgetting to mock dependencies like services in the controller leads to errors during tests.
- Using
@SpringBootTestinstead of@WebMvcTestfor simple controller tests is inefficient. - Not specifying the controller class in
@WebMvcTestcan load unwanted controllers.
java
/* Wrong way: loading full context and no mocking */ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.beans.factory.annotation.Autowired; import org.junit.jupiter.api.Test; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest public class WrongControllerTest { @Autowired private MockMvc mockMvc; @Test public void testEndpoint() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()); } } /* Right way: use @WebMvcTest and mock dependencies */ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.junit.jupiter.api.Test; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(HelloController.class) public class RightControllerTest { @Autowired private MockMvc mockMvc; @MockBean private SomeService someService; // mock service if used in controller @Test public void testEndpoint() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()); } }
Quick Reference
- @WebMvcTest: Loads only controller layer for fast, focused tests.
- MockMvc: Simulates HTTP requests to test controller endpoints.
- @MockBean: Mocks service or repository dependencies used by the controller.
- mockMvc.perform(): Executes HTTP request in test.
- andExpect(): Verifies response status, headers, and body.
Key Takeaways
Use @WebMvcTest to test only the controller layer without loading full context.
Inject MockMvc to simulate HTTP requests and verify controller responses.
Mock dependencies with @MockBean to isolate controller behavior.
Avoid using @SpringBootTest for simple controller tests to keep tests fast.
Always verify HTTP status and response content to ensure correct controller output.