Popular Searches
Popular Course Categories
Popular Courses

Testing Spring Boot Controllers and Services

Testing Spring Boot Controllers and Services

Advanced Java Application Testing and Deployment

Testing Spring Boot Controllers and Services

Course: Advanced Java Training

Topic: Testing Spring Boot Controllers and Services

Course Link: Advanced Java Training Course

Demo Link: Register for a Free Course Demo

Website: JustAcademy


1. Introduction to Testing Spring Boot Controllers and Services

Testing is an essential part of developing reliable Spring Boot applications. It verifies that individual components behave correctly, business rules produce expected results, HTTP endpoints return appropriate responses, and application components work together as intended.

In a typical Spring Boot application, the controller receives HTTP requests, the service implements business logic, and the repository communicates with the database. Each layer has a distinct responsibility and can be tested using different approaches.

For example, an employee management application may provide endpoints to create, retrieve, update, and delete employees. Controller tests verify HTTP status codes and response bodies, while service tests verify business rules such as salary validation, employee creation, and handling missing employee records.

2. Learning Objectives

  • Understand the Spring Boot testing architecture.
  • Differentiate unit tests, slice tests, and integration tests.
  • Test REST controllers using MockMvc and @WebMvcTest.
  • Test service classes using JUnit and Mockito.
  • Mock dependencies and verify method interactions.
  • Validate HTTP responses, request bodies, and exception handling.
  • Test success cases, invalid input, and error scenarios.
  • Configure test dependencies and execute tests using Maven.

3. Understanding the Spring Boot Application Layers

A common Spring Boot REST application separates responsibilities into multiple layers.

HTTP Client
    |
    v
REST Controller
    |
    v
Service Layer
    |
    v
Repository Layer
    |
    v
Database
Layer Responsibility Typical Testing Approach
Controller Handles HTTP requests, input validation, and response formatting. @WebMvcTest, MockMvc
Service Executes business rules and coordinates application operations. JUnit, Mockito, @ExtendWith(MockitoExtension.class)
Repository Reads and writes application data. Repository slice tests or integration tests
Application integration Verifies multiple components working together. @SpringBootTest

4. Types of Testing in Spring Boot

4.1 Unit Testing

Unit testing checks one component in isolation. For example, a service test can mock its repository so that the test focuses on business logic without connecting to a real database.

4.2 Web Layer Testing

Web layer testing focuses on MVC behavior, including request mapping, HTTP status codes, JSON serialization, validation, and exception responses. The @WebMvcTest annotation loads a limited Spring MVC test context.

4.3 Integration Testing

Integration testing verifies that multiple application components work together. The @SpringBootTest annotation can load the full Spring application context. Depending on the test setup, the database may be real, containerized, or replaced with an embedded database.

4.4 Comparison

Feature Unit Test Web Slice Test Integration Test
Primary focus Individual component MVC and HTTP behavior Component collaboration
Spring context Usually not required Limited MVC context Full context commonly used
Dependency handling Mocks or fakes Service dependencies mocked Real or configured test dependencies
Execution speed Usually fastest Usually fast Usually slower

5. Required Dependencies

For a Maven-based Spring Boot project, the Spring Boot test starter provides common testing tools, including JUnit Jupiter, Mockito, and Spring Test support.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Place the dependency inside the project's <dependencies> section. The exact versions are generally managed by the Spring Boot parent or dependency management configuration. For Spring MVC controller tests, ensure the application includes the appropriate Spring MVC web starter.

6. Example Project Structure

src
 ├── main
 │   └── java/com/example/employee
 │       ├── EmployeeApplication.java
 │       ├── controller/EmployeeController.java
 │       ├── service/EmployeeService.java
 │       ├── repository/EmployeeRepository.java
 │       └── model/Employee.java
 └── test
     └── java/com/example/employee
         ├── controller/EmployeeControllerTest.java
         └── service/EmployeeServiceTest.java

Keep tests in the corresponding package structure under src/test/java. This makes test classes easier to discover and maintain.

7. Creating the Employee Model

The following simplified model represents an employee. In a real application, the class might be a JPA entity or a DTO, depending on the role it serves.

package com.example.employee.model;

public class Employee {
    private Long id;
    private String name;
    private String department;

    public Employee() {
    }

    public Employee(Long id, String name, String department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}

8. Creating the Repository Interface

The repository represents the data access layer. For a Spring Data JPA application, it may extend JpaRepository.

package com.example.employee.repository;

import com.example.employee.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository
        extends JpaRepository<Employee, Long> {
}

In unit tests, the repository can be mocked so that database access is not required. Repository behavior itself should be covered separately when database queries and persistence mappings need verification.

9. Creating the Service Layer

The service contains the application's business logic. The example below provides basic employee operations and handles an employee that cannot be found.

package com.example.employee.service;

import com.example.employee.model.Employee;
import com.example.employee.repository.EmployeeRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmployeeService {
    private final EmployeeRepository repository;

    public EmployeeService(EmployeeRepository repository) {
        this.repository = repository;
    }

    public List<Employee> getAllEmployees() {
        return repository.findAll();
    }

    public Employee getEmployeeById(Long id) {
        return repository.findById(id)
            .orElseThrow(() ->
                new IllegalArgumentException("Employee not found"));
    }

    public Employee createEmployee(Employee employee) {
        return repository.save(employee);
    }
}

Constructor injection makes the service easier to test because a mock repository can be passed directly to the constructor.

10. Creating the REST Controller

The controller exposes HTTP endpoints and delegates business operations to the service.

package com.example.employee.controller;

import com.example.employee.model.Employee;
import com.example.employee.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
    private final EmployeeService service;

    public EmployeeController(EmployeeService service) {
        this.service = service;
    }

    @GetMapping
    public List<Employee> getAllEmployees() {
        return service.getAllEmployees();
    }

    @GetMapping("/{id}")
    public Employee getEmployeeById(@PathVariable Long id) {
        return service.getEmployeeById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Employee createEmployee(@RequestBody Employee employee) {
        return service.createEmployee(employee);
    }
}

This example uses a straightforward exception type to keep the focus on testing. In production applications, prefer domain-specific exceptions and a centralized exception handler to map failures to appropriate HTTP responses.

11. Testing Service Classes with JUnit and Mockito

Service unit tests verify business behavior without starting the Spring application context. JUnit Jupiter provides test lifecycle and assertion features, while Mockito creates mock dependencies.

11.1 Important Annotations

Annotation Purpose
@Test Marks a method as a test.
@ExtendWith(MockitoExtension.class) Enables Mockito integration with JUnit Jupiter.
@Mock Creates a mock dependency.
@InjectMocks Creates the test subject and injects its mock dependencies.
@BeforeEach Runs setup logic before each test method.

11.2 Service Test Example

package com.example.employee.service;

import com.example.employee.model.Employee;
import com.example.employee.repository.EmployeeRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class EmployeeServiceTest {

    @Mock
    private EmployeeRepository repository;

    @InjectMocks
    private EmployeeService service;

    @Test
    void shouldReturnAllEmployees() {
        List<Employee> employees = List.of(
            new Employee(1L, "Asha", "IT"),
            new Employee(2L, "Rahul", "HR")
        );

        when(repository.findAll()).thenReturn(employees);

        List<Employee> result = service.getAllEmployees();

        assertEquals(2, result.size());
        assertEquals("Asha", result.get(0).getName());
        verify(repository).findAll();
    }

    @Test
    void shouldReturnEmployeeWhenIdExists() {
        Employee employee = new Employee(1L, "Asha", "IT");
        when(repository.findById(1L))
            .thenReturn(Optional.of(employee));

        Employee result = service.getEmployeeById(1L);

        assertEquals("Asha", result.getName());
        assertEquals("IT", result.getDepartment());
        verify(repository).findById(1L);
    }

    @Test
    void shouldThrowExceptionWhenEmployeeDoesNotExist() {
        when(repository.findById(99L))
            .thenReturn(Optional.empty());

        IllegalArgumentException exception = assertThrows(
            IllegalArgumentException.class,
            () -> service.getEmployeeById(99L)
        );

        assertEquals("Employee not found", exception.getMessage());
        verify(repository).findById(99L);
    }

    @Test
    void shouldSaveEmployee() {
        Employee input = new Employee(null, "Neha", "Finance");
        Employee saved = new Employee(3L, "Neha", "Finance");

        when(repository.save(input)).thenReturn(saved);

        Employee result = service.createEmployee(input);

        assertEquals(3L, result.getId());
        assertEquals("Neha", result.getName());
        verify(repository).save(input);
    }
}

12. Understanding Mockito Stubbing and Verification

Mockito allows a test to define how a dependency behaves and verify how the test subject interacts with it.

Stubbing a Method

when(repository.findById(1L))
    .thenReturn(Optional.of(employee));

This configures the mock to return the supplied employee when the specified method is called with ID 1.

Verifying an Interaction

verify(repository).findById(1L);

This verifies that the service called the repository with the expected argument. Use interaction verification when the interaction is important to the behavior being tested; avoid verifying every implementation detail unnecessarily.

Verifying No Interactions

verifyNoInteractions(repository);

This can be useful when invalid input should be rejected before any repository operation. It should only be used when the absence of interactions is part of the intended behavior.

13. Testing Controllers with @WebMvcTest

The @WebMvcTest annotation loads a focused Spring MVC test context rather than the complete application. It is useful for testing request mappings, JSON handling, validation, status codes, and controller advice.

With Spring Boot versions that support it, @MockitoBean can replace a Spring bean with a Mockito mock. Older projects commonly use @MockBean. Select the annotation supported by the Spring Boot version in your project.

13.1 Controller Test Example

package com.example.employee.controller;

import com.example.employee.model.Employee;
import com.example.employee.service.EmployeeService;
import com.fasterxml.jackson.databind.ObjectMapper;
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import java.util.List;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(EmployeeController.class)
class EmployeeControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @org.springframework.test.context.bean.override.mockito.MockitoBean
    private EmployeeService service;

    @Test
    void shouldReturnAllEmployees() throws Exception {
        when(service.getAllEmployees()).thenReturn(
            List.of(new Employee(1L, "Asha", "IT"))
        );

        mockMvc.perform(get("/api/employees"))
            .andExpect(status().isOk())
            .andExpect(content().contentTypeCompatibleWith(
                MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$[0].id").value(1))
            .andExpect(jsonPath("$[0].name").value("Asha"));
    }

    @Test
    void shouldReturnEmployeeById() throws Exception {
        when(service.getEmployeeById(1L))
            .thenReturn(new Employee(1L, "Asha", "IT"));

        mockMvc.perform(get("/api/employees/{id}", 1L))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.department").value("IT"));
    }

    @Test
    void shouldCreateEmployee() throws Exception {
        Employee request = new Employee(null, "Neha", "Finance");
        Employee saved = new Employee(3L, "Neha", "Finance");

        when(service.createEmployee(org.mockito.ArgumentMatchers.any(Employee.class)))
            .thenReturn(saved);

        mockMvc.perform(post("/api/employees")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(request)))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").value(3))
            .andExpect(jsonPath("$.name").value("Neha"));
    }
}

Version note: The example uses @MockitoBean, available in newer Spring testing versions. If your Spring Boot version does not provide this annotation, use @MockBean from the corresponding Spring Boot test package. Avoid mixing test annotations from incompatible framework versions.

14. Understanding MockMvc

MockMvc performs simulated HTTP requests through Spring MVC without requiring a real web server. It is commonly used with @WebMvcTest.

Method Purpose
perform() Executes a simulated HTTP request.
get() Creates a GET request.
post() Creates a POST request.
put() Creates a PUT request.
delete() Creates a DELETE request.
andExpect() Checks the resulting HTTP response.
jsonPath() Checks values inside JSON responses.

Example:

mockMvc.perform(get("/api/employees/1"))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.name").value("Asha"));

15. Testing HTTP Status Codes

Controllers should return status codes that match the operation's outcome. Tests should verify these codes explicitly.

HTTP Status Typical Use Testing Example
200 OK Successful retrieval or update returning a response. status().isOk()
201 Created A resource was successfully created. status().isCreated()
204 No Content A successful operation with no response body. status().isNoContent()
400 Bad Request Invalid input or malformed request. status().isBadRequest()
404 Not Found The requested resource does not exist. status().isNotFound()
500 Internal Server Error An unexpected server failure. status().isInternalServerError()

The correct status depends on the API contract. For example, a missing employee is often represented as 404, but the application must explicitly map the relevant exception to that response.

16. Testing Request and Response JSON

REST APIs commonly exchange JSON. Controller tests should verify that the application accepts valid JSON and returns the expected JSON fields.

Request Example

{
  "name": "Neha",
  "department": "Finance"
}

Response Example

{
  "id": 3,
  "name": "Neha",
  "department": "Finance"
}

Test Assertions

mockMvc.perform(post("/api/employees")
        .contentType(MediaType.APPLICATION_JSON)
        .content(objectMapper.writeValueAsString(request)))
    .andExpect(status().isCreated())
    .andExpect(jsonPath("$.name").value("Neha"))
    .andExpect(jsonPath("$.department").value("Finance"));

Using Jackson's ObjectMapper avoids manually building JSON strings and reduces errors caused by escaping or formatting.

17. Testing Validation in Controllers

Spring Boot applications often use Jakarta Bean Validation annotations such as @NotBlank, @Email, @Size, and @Positive to validate incoming data.

For example, a request DTO can define basic employee validation rules:

package com.example.employee.model;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public class EmployeeRequest {
    @NotBlank(message = "Name is required")
    @Size(max = 100, message = "Name must be at most 100 characters")
    private String name;

    @NotBlank(message = "Department is required")
    private String department;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}

To activate request validation, add @Valid to the controller parameter and ensure the validation dependency is included in the project.

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Employee createEmployee(
        @jakarta.validation.Valid
        @RequestBody EmployeeRequest request) {
    Employee employee = new Employee(
        null, request.getName(), request.getDepartment());
    return service.createEmployee(employee);
}

A test can then send an invalid request and verify that the controller returns a 400 response. The exact response body depends on the application's exception handling configuration.

mockMvc.perform(post("/api/employees")
        .contentType(MediaType.APPLICATION_JSON)
        .content("{\"name\":\"\",\"department\":\"IT\"}"))
    .andExpect(status().isBadRequest());

18. Testing Exception Handling

Applications should return clear, consistent HTTP responses when an operation fails. A global exception handler implemented using @RestControllerAdvice can translate application exceptions into appropriate HTTP status codes.

Example Exception Handler

package com.example.employee.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ResponseStatus;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ProblemDetail handleNotFound(
            IllegalArgumentException exception) {
        return ProblemDetail.forStatusAndDetail(
            HttpStatus.NOT_FOUND, exception.getMessage());
    }
}

For production code, use a dedicated not-found exception rather than mapping every IllegalArgumentException to 404. Invalid arguments may represent client errors that should instead return 400.

Testing the Error Response

@Test
void shouldReturnNotFoundWhenEmployeeDoesNotExist() throws Exception {
    when(service.getEmployeeById(99L))
        .thenThrow(new IllegalArgumentException("Employee not found"));

    mockMvc.perform(get("/api/employees/99"))
        .andExpect(status().isNotFound())
        .andExpect(jsonPath("$.detail")
            .value("Employee not found"));
}

This test verifies the behavior of the MVC layer and exception handler together. The response property names depend on the selected error format and Spring version, so align assertions with the API's actual response contract.

19. Testing Controller and Service Responsibilities Separately

A controller test should generally verify HTTP behavior while mocking the service. A service test should verify business rules while mocking repositories or other external dependencies.

Scenario Controller Test Service Test
Request mapping Yes No
HTTP status and JSON format Yes No
Business calculations Usually not directly Yes
Repository interaction Usually mocked indirectly through service Yes, when relevant
Bean validation Yes Test domain rules separately if needed
Database query correctness Not in a controller slice test Use repository or integration tests

20. Testing with @SpringBootTest

The @SpringBootTest annotation loads the Spring application context and is useful when the test must verify that several real components work together.

package com.example.employee;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
class EmployeeApplicationTest {

    @Test
    void applicationContextLoads() {
        assertNotNull(true);
    }
}

The example demonstrates the basic annotation but is not a meaningful application behavior test. A useful integration test should call a service or endpoint and verify an actual result. For example, it could create an employee through the service and verify that the employee can be retrieved. If the test writes to a database, configure a dedicated test database and clean up data appropriately.

21. Testing a Full HTTP Flow

When an integration test needs to exercise the full application stack, Spring Boot can start the application on a random port.

@SpringBootTest(webEnvironment =
    SpringBootTest.WebEnvironment.RANDOM_PORT)
class EmployeeApiIntegrationTest {
    // Inject TestRestTemplate or WebTestClient.
    // Send requests to the running application.
    // Assert status codes and response bodies.
}

Choose TestRestTemplate or WebTestClient based on the project's configuration and testing requirements. Full-stack tests are useful for verifying actual HTTP communication, filters, serialization, and integration between application layers.

22. Common Testing Mistakes

  • Testing only successful scenarios: Include invalid input, missing records, and dependency failures.
  • Loading the entire context for every test: Use unit tests or MVC slice tests when they meet the testing goal.
  • Using a real database in every unit test: Mock repository dependencies for service unit tests and reserve database testing for appropriate integration tests.
  • Over-mocking: Mock external dependencies, not the behavior you are trying to verify.
  • Ignoring HTTP status codes: Assert the API's intended status code for each scenario.
  • Testing private methods directly: Prefer verifying observable behavior through public methods.
  • Using shared mutable test data: Create isolated data for each test to avoid order-dependent results.
  • Leaving exception behavior undefined: Define and test consistent error responses.
  • Relying on deprecated test APIs without checking versions: Match annotations and dependencies to the Spring Boot version used by the project.

23. Best Practices for Spring Boot Testing

  • Write small tests that focus on one behavior at a time.
  • Use descriptive test names, such as shouldReturnNotFoundWhenEmployeeDoesNotExist.
  • Follow the Arrange, Act, Assert pattern.
  • Use constructor injection in application components to simplify unit testing.
  • Use @WebMvcTest for controller behavior and Mockito for service dependencies.
  • Use JUnit assertions to verify results and Mockito verification only when relevant.
  • Test boundary conditions, invalid data, and exceptional situations.
  • Keep test fixtures readable and avoid unnecessary setup.
  • Use isolated databases or Testcontainers when verifying database integration.
  • Run tests automatically in the project's continuous integration pipeline.

24. Running Tests with Maven

To execute tests using Maven, run the following command from the project root:

mvn test

To build the project and run its verification lifecycle, use:

mvn verify

To execute a specific test class, use:

mvn -Dtest=EmployeeServiceTest test

Review the test report and fix failing assertions, context initialization errors, missing dependencies, or incompatible framework annotations.

25. Practical Project: Employee Management API Testing

Build a small employee management application and create a test suite for its main operations.

Project Requirements

  • Retrieve all employees.
  • Retrieve an employee by ID.
  • Create an employee.
  • Validate employee names and department values.
  • Return a consistent error response when an employee is not found.
  • Keep controller and service tests separate.
  • Add integration tests for persistence and end-to-end behavior.

Suggested Test Cases

Test Case Expected Result
Retrieve an existing employee 200 OK with correct JSON fields
Retrieve an unknown employee 404 Not Found according to the API contract
Create a valid employee 201 Created with the saved employee
Create an employee with a blank name 400 Bad Request when validation is configured
Service receives a repository result Expected employee is returned
Service cannot find the requested employee Expected domain exception is thrown
Repository save returns a saved entity Service returns the saved entity

26. Exercises for Practice

  1. Write a service unit test that verifies the result of getAllEmployees().
  2. Write a test that verifies the service throws an exception for a missing employee.
  3. Create a controller test for the GET endpoint using MockMvc.
  4. Test the POST endpoint with a valid JSON request.
  5. Add validation to an employee request DTO and test invalid input.
  6. Create a global exception handler and test the response for a missing employee.
  7. Write an integration test that verifies an employee can be saved and retrieved.
  8. Run the full test suite through Maven and inspect the reports.

27. Interview Questions and Answers

Q1. What is unit testing in Spring Boot?

Unit testing verifies an individual class or component independently, usually with its dependencies mocked or replaced by simple test doubles.

Q2. What is the purpose of @WebMvcTest?

It loads a focused Spring MVC test context to test controllers, request mapping, validation, serialization, and related web behavior without loading the complete application.

Q3. What is MockMvc?

MockMvc performs simulated HTTP requests through Spring MVC and allows assertions against status codes, headers, and response bodies without starting a real server.

Q4. What is Mockito used for?

Mockito creates mock dependencies, defines their responses, and verifies interactions with those dependencies.

Q5. What is the difference between @Mock and @InjectMocks?

@Mock creates a mock dependency. @InjectMocks creates the test subject and attempts to inject its mock dependencies.

Q6. What is @SpringBootTest?

It loads the Spring Boot application context and is useful for tests that require multiple real application components to work together.

Q7. How do you test a controller without calling the database?

Use @WebMvcTest and replace the service dependency with a mock so that controller behavior can be tested independently of persistence.

Q8. How do you test an exception in a service?

Use JUnit's assertThrows() and verify the expected exception type and, where appropriate, its message.

Q9. How do you test JSON response fields?

Use MockMvc's jsonPath() assertions to verify values at specific paths in the response JSON.

Q10. What is the purpose of @RestControllerAdvice?

It provides centralized handling of controller exceptions and can return consistent HTTP status codes and error response bodies.

Q11. Why should controller and service tests be separate?

Separating tests clarifies responsibility, makes failures easier to diagnose, and allows each layer to be tested at the appropriate level.

Q12. What is an integration test?

An integration test checks whether multiple components or systems work together correctly, such as a service, repository, and database.

Q13. How can controller validation be tested?

Send an invalid request through MockMvc and assert the expected validation status and error response.

Q14. How do you run Spring Boot tests with Maven?

Use mvn test to execute the project's tests, or mvn verify to run the verification lifecycle.

Q15. Should every test use @SpringBootTest?

No. Unit tests and MVC slice tests are usually faster and more focused. Use a full application context when integration behavior needs to be verified.

28. Quick Revision Checklist

  • Understand controller, service, and repository responsibilities.
  • Use JUnit for test execution and assertions.
  • Use Mockito to isolate dependencies in service unit tests.
  • Use @WebMvcTest and MockMvc for HTTP-layer tests.
  • Assert status codes, JSON fields, validation, and exception responses.
  • Use @SpringBootTest for tests requiring the full application context.
  • Match testing annotations to the Spring Boot version.
  • Run tests using Maven and review the results.

29. Conclusion

Testing Spring Boot controllers and services helps ensure that an application handles requests correctly, follows business rules, validates input, and responds consistently to errors. JUnit and Mockito are suitable for focused service unit tests, while MockMvc and @WebMvcTest are useful for controller tests. Integration tests using @SpringBootTest can verify that multiple layers work together.

A balanced test suite combines fast unit tests, focused web tests, and selected integration tests. This approach improves code quality, reduces regressions, and makes Spring Boot applications easier to maintain.


Learn More with JustAcademy

Explore the Advanced Java Training Course to learn more about Java development, Spring Boot, application architecture, and testing.

Register for a Course Demo

Visit the JustAcademy Website for additional learning resources and training information.

Previous Next
whatsapp