Spring Boot MockMVC Testing with Example Project

Last Updated : 16 Mar, 2026

Spring Boot MockMVC is a testing framework provided by Spring that allows developers to test the web layer (controllers) of a Spring Boot application without starting the actual server. It simulates HTTP requests such as GET, POST, PUT, and DELETE and verifies the response returned by the controller.

  • Tests Spring MVC controllers without running the actual server.
  • Simulates HTTP requests and responses.
  • Helps verify status, response body, model data, and view names

Common MockMvc Methods

The MockMvc framework provides several methods to simulate HTTP requests and validate the responses returned by Spring MVC controllers.

MethodPurpose
perform()Executes HTTP request
andExpect()Verifies response
status().isOk()Checks HTTP status
content().string()Checks response body
jsonPath()Verifies JSON data

Steps to Implement MockMVC Testing

Step 1: Create a Spring Boot Project

  • Go to Spring Initializr and create a new Spring Boot project.
  • Add the dependencies.
  • Download and open the project in your IDE.

Project Structure:

Project Structure
 

Add Spring Boot Web and Test dependencies in pom.xml.

pom.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>test-springmvc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-springmvc</name>
    <description>Sample Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Step 2: Create Model Class

Create a simple Employee class with required methods.

GeekEmployee.java

Java
public class GeekEmployee {

    private Long employeeId;
    private String firstName;
    private String lastName;
    private int salary;
    
    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public GeekEmployee(String firstName, String lastName, int salary) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.salary = salary;
    }    

    public Long getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(Long employeeId) {
        this.employeeId = employeeId;
    }


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }   
    
}

Step 3: Create Generator class

Create GeekEmployeeIdGenerator.java .

GeekEmployeeIdGenerator.java

Java
public class GeekEmployeeIdGenerator {

    private static long employeeId = 1000;

    public static synchronized long value() {
        return employeeId++;
    }
}

Step 4: Create Service Layer

Write business logic in a service class.

GeekEmployeeService.java

Java
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.springframework.stereotype.Service;

import com.gfg.gfgsample.domain.GeekEmployee;
import com.gfg.gfgsample.util.GeekEmployeeIdGenerator;

@Service
public class GeekEmployeeService {    
    Map<Long, GeekEmployee> geekEmployees = new HashMap<>();

    // Return all geekEmployees
    public Collection<GeekEmployee> findAll(){
        return geekEmployees.values();
    }
 
    // Find the geekEmployee with this id
    public Optional<GeekEmployee> findById(Long employeeId) {
        GeekEmployee geekEmployee = null;
 
        if (geekEmployees.containsKey(employeeId)) geekEmployee = geekEmployees.get(employeeId);
            return Optional.ofNullable(geekEmployee);
    }
         
    // Save a new GeekEmployee   
    public GeekEmployee save(GeekEmployee geekEmployee) {
        geekEmployee.setEmployeeId(GeekEmployeeIdGenerator.value());
        geekEmployees.put(geekEmployee.getEmployeeId(), geekEmployee);
        return geekEmployee;
    }
     
    // Update the GeekEmployee with this id
    public Optional<GeekEmployee> update(GeekEmployee geekEmployee) {
        GeekEmployee geekEmployee1 = geekEmployees.get(geekEmployee.getEmployeeId());
 
        if (geekEmployee1 != null) {
            geekEmployees.put(geekEmployee.getEmployeeId(), geekEmployee);
            geekEmployee1 = geekEmployees.get(geekEmployee.getEmployeeId());
        }
        return Optional.ofNullable(geekEmployee1);
    }
     
    // Delete GeekEmployee with this id
    public Optional<GeekEmployee> delete(Long employeeId) {
        GeekEmployee geekEmployee1 = geekEmployees.get(employeeId);
 
        if (geekEmployee1 != null) {
            geekEmployees.remove(employeeId);
        }
        return Optional.ofNullable(geekEmployee1);
    }

}

The service layer handles employee data operations.

Step 5: Create Controller Layer

Create a Spring MVC Controller.

GeekEmployeeMvcController.java

Java
package com.gfg.gfgsample.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.gfg.gfgsample.service.GeekEmployeeService;

@Controller
@RequestMapping("mvc")
public class GeekEmployeeMvcController {
    
    private final GeekEmployeeService geekEmployeeService;
    
    public GeekEmployeeMvcController(GeekEmployeeService geekEmployeeService) {
        this.geekEmployeeService = geekEmployeeService;
    }
    
    @GetMapping("geekemployees")
    public String getGeekEmployees(Model model) {
        model.addAttribute("geekemployees", geekEmployeeService.findAll());
        return "geekemployee-list";
    }

}

GeekEmployeeRestController.java

Java
import java.net.URI;
import java.util.Collection;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.gfg.gfgsample.domain.GeekEmployee;
import com.gfg.gfgsample.service.GeekEmployeeService;
import com.gfg.gfgsample.util.GeekEmployeeIdGenerator;

@RestController
@RequestMapping("geekemployees")
public class GeekEmployeeRestController {

    private final GeekEmployeeService geekEmployeeService;
    
    public GeekEmployeeRestController(GeekEmployeeService service) {
        this.geekEmployeeService = service;
    }
    
    @GetMapping
    Collection<GeekEmployee> readGeekEmployees(){
        return this.geekEmployeeService.findAll();
    }
    
    @GetMapping("/{id}")
    GeekEmployee readGeekEmployee(@PathVariable Long id) {
        return this.geekEmployeeService.findById(id)
                .orElseThrow(GeekEmployeeNotFoundException::new);
    }
    
    @PostMapping
    ResponseEntity<?> addEmployee(@RequestBody GeekEmployee geekEmployee){
        // Hack to get Mockito test to work
        // Will fix this soon
        // When not running JUnit tests
        // These statements should be commented out
        // and the statements below should be uncommented
        this.geekEmployeeService.save(geekEmployee);
        URI location = ServletUriComponentsBuilder
                .fromCurrentRequest()
                .path("/{id}")
                .buildAndExpand(GeekEmployeeIdGenerator.value())
                .toUri();
        


        return ResponseEntity.created(location).build();        
    }
    
    @PutMapping
    GeekEmployee updateEmployee(@RequestBody GeekEmployee geekEmployee) {
        return this.geekEmployeeService.update(geekEmployee)
                .orElseThrow(GeekEmployeeNotFoundException::new);
    }
    
    @DeleteMapping("/{id}")
    void deleteStudent(@PathVariable Long id) {
        this.geekEmployeeService.delete(id)
            .orElseThrow(GeekEmployeeNotFoundException::new);
    }        
    
    @ResponseStatus(HttpStatus.NOT_FOUND)
    class GeekEmployeeNotFoundException extends RuntimeException {

        private static final long serialVersionUID = 1L;

        public GeekEmployeeNotFoundException() {
            super("Employee does not exist");
        }
    }
}

Step 6: Create the html page.

Make the html list of employee.

geekemployee-list.html

HTML
<html xmlns="https://www.w3.org/1999/xhtml/"
   xmlns:th="https://www.thymeleaf.org/">
   <head>
      <title>Employee List</title>
      <!-- Latest compiled and minified CSS -->
      <link rel="stylesheet"
         href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
         integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
         crossorigin="anonymous" />
   </head>
   <body>
      <div class="container">
         <div class="page-header">
            <h1>Employee List</h1>
         </div>
         <div class="container">
            <div class="column">
               <table class="table datatable">
                  <tr>
                     <th>First Name</th>
                     <th>Last Name</th>
                     <th>Salary</th>
                  </tr>
                  <tr th:each="geekemployee : ${geekemployees}">
                     <td th:text="${geekemployee.firstName}">Joe</td>
                     <td th:text="${geekemployee.lastName}">Tribiani</td>
                     <td th:text="${geekemployee.salary}">100000</td>
                  </tr>
               </table>
            </div>
         </div>
      </div>
   </body>
</html>

Step 7: Run the Main class

Start the main class .

TestSpringmvcApplication.java

Java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.gfg.gfgsample.domain.GeekEmployee;
import com.gfg.gfgsample.service.GeekEmployeeService;

@SpringBootApplication
public class TestSpringmvcApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSpringmvcApplication.class, args);
    }

    @Bean
    CommandLineRunner init(GeekEmployeeService geekEmployeeService) {
        return args -> {
            geekEmployeeService.save(new GeekEmployee("Rachel", "Green", 100000));
            geekEmployeeService.save(new GeekEmployee("Monica", "Geller", 40000));
            geekEmployeeService.save(new GeekEmployee("Phoebe", "", 45000));
        };
    }
}

After running the spring application, our console is as follows

Output on mvc/geekemployees

Testing Part:

GeekEmployeeMvcWebTest.java

Java
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import java.util.List;

import org.hamcrest.Matchers;
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 com.gfg.gfgsample.domain.GeekEmployee;
import com.gfg.gfgsample.service.GeekEmployeeService;
 
@WebMvcTest(controllers = GeekEmployeeMvcController.class)
class GeekEmployeeMvcWebTest {
 
    @Autowired
    MockMvc mockMvc;
 
    @MockBean
    GeekEmployeeService geekEmployeeService;
 
    @Test
    void checkForGeekEmployeeListView() throws Exception {
        GeekEmployee ge1 = new GeekEmployee("Rachel", "Green", 50000);
        GeekEmployee ge2 = new GeekEmployee("Monica", "Geller", 40000);
        GeekEmployee ge3 = new GeekEmployee("Phoebe", "", 45000);
        List<GeekEmployee> geekEmployeeList = List.of(ge1, ge2, ge3);
 
        when(geekEmployeeService.findAll()).thenReturn(geekEmployeeList);
 
        this.mockMvc.perform(get("/mvc/geekemployees"))
            .andExpect(status().isOk())
            .andExpect(view().name("geekemployee-list"))
            .andExpect(model().attribute("geekemployees", geekEmployeeList))
            .andExpect(model().attribute("geekemployees", Matchers.hasSize(3)))
            .andDo(print());
    }
 
}

Testcase Output:

Testcase Output

GeekEmployeeRestWebTest.java

Java
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.Optional;

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 com.gfg.gfgsample.domain.GeekEmployee;
import com.gfg.gfgsample.service.GeekEmployeeService;

@WebMvcTest(controllers = GeekEmployeeRestController.class)
class GeekEmployeeRestWebTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean
    GeekEmployeeService geekEmployeeService;
    
    @Test
    void whenReadGeekEmployee_returnJsonContent() throws Exception {
        GeekEmployee rachel = new GeekEmployee("Rachel", "Green", 100000);
        rachel.setEmployeeId(1000L);
        
        when(geekEmployeeService.findById(1000L)).thenReturn(Optional.of(rachel));
        
        this.mockMvc.perform(get("/geekemployees/1000"))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString(
                "{\"employeeId\":1000,\"firstName\":\"Rachel\",\"lastName\":\"Green\",\"salary\":100000}")))
            .andDo(print());
    }
}

Testcase Output:

Testcase Output
Comment

Explore