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.
| Method | Purpose |
|---|---|
| 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:

Add Spring Boot Web and Test dependencies in pom.xml.
pom.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
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
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
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
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
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 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
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
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:

GeekEmployeeRestWebTest.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:
