0
0
SpringbootHow-ToBeginner · 4 min read

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 @WebMvcTest causes 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 @SpringBootTest instead of @WebMvcTest for simple controller tests is inefficient.
  • Not specifying the controller class in @WebMvcTest can 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.