CodeGym /Courses /Module 5. Spring /Lecture 138: Introduction to MockMvc for testing MVC cont...

Lecture 138: Introduction to MockMvc for testing MVC controllers

Module 5. Spring
Level 9 , Lesson 7
Available

When it comes to Spring MVC and our REST controllers, it's important to make sure the app handles requests correctly. Imagine your controller is supposed to do a complex job like accepting a pizza order, but instead it sends you khachapuri. MockMvc lets you test scenarios like that (well, not literally about pizza, but about correct request handling).

MockMvc helps you:

  1. Verify routes (for example, GET /api/orders/{id}).
  2. Make sure endpoints return correct HTTP statuses (200, 404).
  3. Check that the response body contains exactly what you expect (JSON, XML, etc.).
  4. Catch bugs before a QA tester finds them and pokes at your sensitive spots.

MockMvc is part of spring-test — a library that's included in the Spring Framework. So you don't need to install anything extra if you're already using Spring in your project.


Configuring MockMvc

First, let's see how to set up the environment. You can use the @AutoConfigureMockMvc annotation, which will automatically configure MockMvc for your application.

Example setup:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc will be configured automatically

    // Tests will go here
}

If you're feeling heroic and want to set everything up manually, here's how to do it:


@BeforeEach
void setUp() {
    mockMvc = MockMvcBuilders.standaloneSetup(new OrderController()).build();
}

Writing a basic test with MockMvc

Let's try testing the simplest controller. Say we have a controller that returns a greeting message.


@RestController
@RequestMapping("/api/hello")
public class HelloController {

    @GetMapping
    public ResponseEntity<String> sayHello() {
        return ResponseEntity.ok("Hello, world!");
    }
}

Now let's test it:


@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testSayHello() throws Exception {
        mockMvc.perform(get("/api/hello")) // Simulate a GET request
            .andExpect(status().isOk())    // Check that the response status is 200
            .andExpect(content().string("Hello, world!")); // Check that the response body contains "Hello, world!"
    }
}

Let's break down what's happening here:

  1. mockMvc.perform(get("/api/hello")) — we simulate an HTTP GET request.
  2. andExpect(status().isOk()) — we check that HTTP status 200 is returned.
  3. andExpect(content().string("Hello, world!")) — we ensure the response body contains the expected string.

Checking JSON responses

Most of your controllers will probably return JSON. MockMvc makes working with JSON really convenient.

Example controller:


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @GetMapping("/{id}")
    public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {
        OrderDTO order = new OrderDTO(id, "Pizza", 2); // Return a "stub" object
        return ResponseEntity.ok(order);
    }
}

Example DTO class:


public class OrderDTO {
    private Long id;
    private String name;
    private int quantity;

    // Constructors, getters, and setters
}

Now let's write the test:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testGetOrder() throws Exception {
        mockMvc.perform(get("/api/orders/1")) // Simulate a GET request
            .andExpect(status().isOk()) // Check 200 OK status
            .andExpect(jsonPath("$.id").value(1)) // Check the "id" field
            .andExpect(jsonPath("$.name").value("Pizza")) // Check the "name" field
            .andExpect(jsonPath("$.quantity").value(2)); // Check the "quantity" field
    }
}

The key thing here is jsonPath. This method helps extract values from JSON objects and assert them. For example:

  • $.id — this is the path to the id field in the root object.

Checking HTTP headers

If your controller adds custom headers to the response, MockMvc has you covered there too.

Example controller:


@RestController
@RequestMapping("/api/headers")
public class HeaderController {

    @GetMapping
    public ResponseEntity<String> getHeader() {
        return ResponseEntity.ok()
            .header("X-Custom-Header", "HeaderValue")
            .body("Response with a header");
    }
}

Test:


@SpringBootTest
@AutoConfigureMockMvc
public class HeaderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCustomHeader() throws Exception {
        mockMvc.perform(get("/api/headers"))
            .andExpect(status().isOk()) // Check 200 status
            .andExpect(header().string("X-Custom-Header", "HeaderValue")); // Check the header
    }
}

Handling POST requests

Sometimes you need to test endpoints that accept data from the client. Imagine we have a controller that handles creating new orders.

Example controller:


@RestController
@RequestMapping("/api/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody OrderDTO order) {
        order.setId(100L); // Set the created order ID
        return ResponseEntity.status(HttpStatus.CREATED).body(order);
    }
}

Test:


@SpringBootTest
@AutoConfigureMockMvc
public class OrderControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testCreateOrder() throws Exception {
        String orderJson = "{ \"name\": \"Pizza\", \"quantity\": 1 }";

        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON) // Specify content type
                .content(orderJson)) // Send the request body
            .andExpect(status().isCreated()) // Check 201 Created status
            .andExpect(jsonPath("$.id").value(100)) // Check that ID is set
            .andExpect(jsonPath("$.name").value("Pizza")) // Check the name
            .andExpect(jsonPath("$.quantity").value(1)); // Check the quantity
    }
}

Tips and common mistakes

When using MockMvc, make sure that:

  1. You specify routes correctly. People often forget to set the base @RequestMapping on the controller.
  2. Headers and content types match what your endpoint expects. For example, if you're sending JSON, don't forget contentType(MediaType.APPLICATION_JSON).

If MockMvc throws an error saying it can't find the controller, check whether @SpringBootTest is configured and whether your controller is in the application context.


MockMvc is your first step toward well-tested controllers. In the next lectures we'll dive into writing more advanced tests and explore integration with real databases.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION