Part 2: How Automation Boosts API Quality – Spring Boot + JWT + Full Test Strategy

  • 4.6/5
  • 64
  • Jul 11, 2025

Note: If you haven't already, check out Part 1: Code to Confidence – Spring Boot + JWT Authentication before continuing.

Part 2 shifts focus to test automation. In this phase, you'll build a comprehensive testing pipeline that validates every change — from isolated units to full-stack security — using industry-standard tools and practices:

  • Unit tests with JUnit 5 and Mockito
  • Integration tests using Spring Boot Test and Testcontainers
  • Contract tests powered by Spring Cloud Contract and PACT
  • End-to-end (E2E) tests using RestAssured
  • Security testing

By automating these layers, you'll create a repeatable, trustworthy testing strategy that supports confident, continuous delivery of your Spring Boot API.

1. Unit Testing (Controller, Service, Repository, Model, DTO, Configs, etc.)

Unit testing focuses on verifying individual components of your application in isolation, without relying on external dependencies like databases or full Spring context.


Unit Testing the Controller Layer

Unit testing the controller layer focuses on testing individual controller methods in isolation, without involving the full Spring Boot context or actual HTTP requests. This ensures that request handling logic, input validation, and response formatting are working correctly.

AuthControllerTest.java


StudentControllerTest.java


Unit Testing the Service Layer

Unit testing the service layer focuses on verifying the business logic independently of other layers like controllers or databases. These tests ensure that your core logic behaves correctly under different scenarios, without depending on web or data layers.

AuthServiceTest.java


CustomUserDetailsServiceTest.java


StudentServiceTest.java


Unit Testing the Repository Layer

The repository layer interacts directly with the database and is responsible for data persistence and retrieval. In Spring Boot, repositories are typically interfaces that extend JpaRepository or similar Spring Data interfaces.


StudentRepositoryTest.java


UserRepositoryTest.java


Unit Testing the DTOs

DTOs (Data Transfer Objects) are simple Java objects used to transfer data between layers, often without any business logic. While they are typically considered “dumb” objects, unit testing DTOs can still be useful in certain cases.

Common scenarios where DTO unit tests are beneficial include:

  • Validation Annotations: Testing that @NotNull, @Email, @Size, etc. work as expected using a validation framework.
  • Custom Logic: If DTOs contain computed fields or methods, such logic should be tested independently.
  • Serialization/Deserialization: Ensuring that DTOs correctly map to/from JSON using tools like Jackson or Gson.

Unit Testing the Security Configs

Unit testing security configurations ensures that your authentication, authorization, and access control rules are correctly enforced in your Spring Boot application. These tests help validate that endpoints are properly secured, roles are respected, and filters behave as expected.


2. Integration Testing

This integration test validates the complete flow of the StudentController REST API using TestRestTemplate. The test runs with a real Spring Boot context (@SpringBootTest(webEnvironment = RANDOM_PORT)) and performs real HTTP calls to the application.

It begins by registering and logging in an admin user to obtain a valid JWT token. This token is then used to authenticate and perform full CRUD operations on the /students endpoint.

  • Create: Adds a new student using POST
  • Read: Fetches all students and a specific student by ID
  • Update: Modifies the student data using PUT
  • Delete: Removes the student and verifies deletion

Each step includes assertions to check HTTP status codes and response content, ensuring the backend works correctly across all layers—authentication, controller, service, and repository.


3. E2E Testing using RestAssured

This end-to-end (E2E) test uses RestAssured to simulate real client interactions with the Spring Boot application. It runs with the full application context using @SpringBootTest(webEnvironment = RANDOM_PORT) and communicates over HTTP through a randomly assigned port.

The test covers the full authentication and data flow, including:

  • User Registration: A new admin user is created using the /auth/register endpoint.
  • Login: The registered user logs in and retrieves a JWT token from the /auth/login endpoint.
  • Student Creation: A new student is created via the /students endpoint using the JWT for authorization.
  • Fetch Students: The test fetches all students to verify the new entry exists.

This E2E test ensures that the entire application—from HTTP layer to database—is functioning correctly, and that secured endpoints are working as intended under realistic usage.


4. Functional Testing (User Journey)

This test simulates a real user journey through the application, verifying core functionality from registration to resource access. Using TestRestTemplate and a full Spring Boot context, it validates the entire flow in a stateful manner.

The test performs the following steps in sequence:

  • User Registration: A new admin user is registered using the /auth/register endpoint.
  • User Login: The same user logs in to obtain a JWT token via the /auth/login endpoint.
  • Create Student: A new student is added to the system using an authorized POST request to /students.
  • Retrieve Student: The newly created student is fetched using their ID to confirm creation and correctness.

This functional test validates the user experience from start to finish, ensuring that the authentication process, protected endpoints, and student data operations work together seamlessly.

Full User Journey Test (Register → Login → Access Protected Resource)

5. Security Testing (Token)

This test ensures that protected endpoints are properly secured and only accessible with a valid JWT token. It uses MockMvc for simulating HTTP requests without starting a full server, enabling fast and isolated testing.

Two scenarios are tested:

  • Access without Token: A request to the protected /users endpoint is made without a token, expecting a 403 Forbidden response.
  • Access with Valid Token: A user is dynamically registered and logged in to generate a valid JWT. This token is then used to access the /students endpoint, expecting a successful 200 OK response.

This test verifies both positive and negative security flows, ensuring that the application:

  • Blocks unauthorized access to secured resources.
  • Allows access when a valid JWT is provided in the Authorization header.

Such testing is critical to validate the robustness of your authentication and authorization mechanisms.

6. Load Testing

Load testing helps assess how the system performs under heavy traffic and concurrent user load. Apache JMeter is used here to simulate multiple users sending requests to the Spring Boot application, measuring response times, throughput, and error rates.

Performance Testing with JMeter

We'll simulate high-load scenarios on endpoints like:

  • POST /auth/login
  • GET /students
  • POST /students
  • DELETE /students/{id}

Prerequisites:

  • JMeter installed
  • Java installed (JDK 8+)
  • Spring Boot app running on localhost:8080
  • Registered user (for secured endpoints)

Step 1: Start Your Spring Boot App

Make sure your API is running locally (on http://localhost:8080) before testing.

Step 2: Launch JMeter

  1. Go to: https://jmeter.apache.org/download_jmeter.cgi. Download the .tgz (tar.gz) file.
  2. tar -xvzf apache-jmeter-<version>.tgz
  3. mv apache-jmeter-<version> /Applications/
  4. cd /Applications/apache-jmeter-<version>/bin
  5. ./jmeter


Panch Prayag

Step 3: Create a Test Plan

Right-click Test Plan → Add → Threads (Users) → Thread Group

Set:
Number of Threads (users) = 100
Ramp-Up Period (seconds) = 10
Loop Count = 5

Step 4: Add HTTP Request Defaults

Right-click Thread Group → Add → Config Element → HTTP Request Defaults

Set:
Server Name = localhost
Port = 8080
Protocol = http

Step 5: Add HTTP Header Manager (for JWT token)

If you're testing secured endpoints:
Right-click Thread Group → Add → Config Element → HTTP Header Manager

Add header:
Name: Authorization
Value: Bearer <your-JWT-token>

Step 6: Add HTTP Sampler(s)

For each endpoint:

Example 1: GET /students
Right-click Thread Group → Add → Sampler → HTTP Request
Method: GET
Path: /students

Example 2: POST /students
Method: POST
Path: /students

Click Body Data and paste:

{
  "name": "JMeter Student",
  "email": "jmeter@mail.com",
  "course": "Performance Testing"
}

Add Content-Type: application/json in Header Manager.

Step 7: Add Listeners

To view results:

  • Right-click Thread Group → Add → Listener
  • View Results Tree
  • Summary Report
  • Aggregate Report
  • Graph Results (optional)

Step 8: Run the Test

Click Start (green triangle) → Let the test finish

Analyze metrics:

  1. Throughput (requests/sec)
  2. Average response time
  3. 90th/95th percentile latency
  4. Errors

JMeter HTML Dashboard (Recommended)

If you run JMeter in headless mode, it generates detailed graphs:

/jmeter -n -t student-management-api.jmx -l student-management-api-results.jtl -e -o ~/Desktop/student-management-api-results


Panch Prayag

7. Code Coverage with Jacoco

JaCoCo (Java Code Coverage) is a widely used, open-source tool that measures how much of your Java code is executed during test runs. It provides detailed insights to help improve test effectiveness and identify untested code paths.

When integrated with your Spring Boot project, JaCoCo generates comprehensive coverage reports that include:

  • Line Coverage: Tracks the number of lines of code executed during tests.
  • Branch Coverage: Verifies whether both true and false branches of conditionals (like if statements) are covered.
  • Method/Class Coverage: Checks which methods and classes were executed by tests.

Step 1: Add JaCoCo to Your pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.11</version>
      <executions>
        <execution>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
        <execution>
          <id>report</id>
          <phase>verify</phase>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Step 3: Run Tests and Generate Report

Run the following Maven command:

mvn clean verify

This will:

  • Run all your tests (unit, integration, etc.)
  • Generate a coverage report in: target/site/jacoco/index.html


Panch Prayag

Step 4: Enforce Minimum Coverage Rules (Optional)

<configuration>
  <rules>
    <rule>
      <element>BUNDLE</element>
      <limits>
        <limit>
          <counter>LINE</counter>
          <value>COVEREDRATIO</value>
          <minimum>0.80</minimum>
        </limit>
      </limits>
    </rule>
  </rules>
</configuration>

To exclude DTOs, configs, etc.:

<configuration>
  <excludes>
    <exclude>**/dto/**</exclude>
    <exclude>**/config/**</exclude>
  </excludes>
</configuration>

8. Contract Testing & Schema Validation

Contract Testing verifies that the API provider (Spring Boot backend) and the consumer (frontend/microservice) agree on:

  • What the API expects as input
  • What it returns as output
  • What the structure and status codes will be

This ensures early failure detection if someone changes the API unintentionally — even before full integration testing.

There are many tools used for Contract Testing & Schema Validation like: Spring Cloud Contract, Pact, OpenAPI + Swagger, JSON Schema Validator and RestAssured.

Use Case: Validate POST /students response contract

Consumer expects:

{
  "id": 1,
  "name": "John",
  "email": "john@mail.com",
  "course": "Math"
}

1) Option 1: Spring Cloud Contract

1. Add Dependencies

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-verifier</artifactId>
</dependency>
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>4.3.0</version>
</plugin>

2. Define Contract (Groovy or YAML)

src/test/resources/contracts/student/post_student_should_return_created.groovy

3. Run and Generate Tests

mvn clean install

2) Option 2: Pact (Consumer-Driven Contracts)

  1. Consumer (frontend) writes a pact
  2. Provider (Spring Boot) verifies it using:
<dependency>
  <groupId>au.com.dius.pact.provider</groupId>
  <artifactId>spring</artifactId>
</dependency>

More at: A Guide to Pact Contract Testing in Spring Boot Applications

Conclusion:

With this two-part journey complete, you've not only built a secure, production-ready Spring Boot REST API with JWT authentication, but also fortified it with a comprehensive suite of automated tests—spanning unit, integration, contract, end-to-end, functional, and security layers.

From manual validation via curl and Swagger UI to rigorous testing pipelines powered by RestAssured, JMeter, and JaCoCo, you're now equipped to ship code with confidence and clarity. This foundation enables faster iterations, safer deployments, and a future-proof development workflow. Happy coding—and even happier testing!

🔗 View the complete project on GitHub: student-management-api

Index
How to Implement PostgreSQL Full-Text Search with Spring Boot

15 min

Spring's transaction management with the @Transactional annotation

9 min

Spring Boot Rest APIs with PostgreSQL (Spring Boot + Rest APIs)

15 min

Caching in Spring Boot (@Cacheable, @CacheEvict & @CachePut)

21 min

Declarative REST Client in Spring Boot (Spring 6 HTTP Interface)

13 min

A Guide to Pact Contract Testing in Spring Boot Applications

10 min

Circuit Breaker in Spring Boot (Spring Cloud Circuit Breaker + Resilience4j)

12 min

Handling Concurrent Service Calls in a Spring Boot Application: CompletableFuture and @Async

11 min

Profiling a Spring Boot application with Pyroscope

7 min

Service discovery in Spring Boot (Spring Cloud + Netflix Eureka)

9 min

Dockerize Spring Boot app and Push image to DockerHub (Spring Boot + DockerHub)

4 min

Creating a Jenkins Pipeline for Spring Boot application

2 min

Circuit Breaker Pattern in Microservices (Spring BOOT + Resilience4j)

4 min

Monitoring Microservices (Spring Boot + Micrometer + Prometheus + Grafana)

7 min

Edge Server Pattern in Microservices (Spring Cloud Gateway)

7 min

Spring Cloud config server setup with Git

8 min

Distributed Tracing in Microservices (Spring Cloud Sleuth + Zipkin)

9 min

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

24 min

Deploying Spring Boot microservices on Kubernetes Cluster

12 min

Reactive programming in Java with Project Reactor

50 min

Spring Reactive with PostgreSQL (Spring Boot WebFlux + PostgreSQL)

13 min

Spring Reactive, Thymeleaf Hello World (Spring Webflux + Thymeleaf + JS/CSS)

9 min

Problem JSON (application/problem+json) in Spring WebFlux

15 min

Spring Boot Login/Logout (Spring Security + MySql + Thymeleaf)

21 min

Securing Server-to-Server Communication with "Spring Boot" & "OAuth 2"

18 min

Integrating AWS OpenSearch with Spring Boot (Index, Search, Pagination & Aggregation)

8 min

Integrating Elasticsearch with a Spring Boot and PostgreSQL application

16 min

Sending Emails in Spring Boot via SMTP

7 min

How to create a basic Spring 6 project using Maven

5 min

Spring Boot, Thymeleaf Hello World (Spring Boot + Thymeleaf + JS/CSS)

9 min