Open In App

Spring Boot MockMVC Testing with Example Project

Last Updated : 09 Oct, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

In a Spring Boot project, we have to test the web layer. For that, we can use MockMVC. In this tutorial, let us see how to do that by having a sample GeekEmployee bean and writing the business logic as well as the test cases for it.

Example Project

Project Structure:

Project Structure

 

This is a maven project. Let’s start with

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://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>


First, let’s go with the bean class

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;
    }   
      
}


As employeeId is auto-generated, let us create that via

GeekEmployeeIdGenerator.java

Java




public class GeekEmployeeIdGenerator {
  
    private static long employeeId = 1000;
  
    public static synchronized long value() {
        return employeeId++;
    }
}


Service file where we can write our business logic

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);
    }
  
}


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");
        }
    }
}


Start up the file that can run as the java application

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));
        };
    }
}


geekemployee-list.html

HTML




   xmlns:th="http://www.thymeleaf.org">
   <head>
      <title>Employee List</title>
      <!-- Latest compiled and minified CSS -->
      <link rel="stylesheet"
         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>


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

 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads