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 a403 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 successful200 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
- Go to: https://jmeter.apache.org/download_jmeter.cgi. Download the .tgz (tar.gz) file.
- tar -xvzf apache-jmeter-<version>.tgz
- mv apache-jmeter-<version> /Applications/
- cd /Applications/apache-jmeter-<version>/bin
- ./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:
- Throughput (requests/sec)
- Average response time
- 90th/95th percentile latency
- 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)
- Consumer (frontend) writes a pact
- 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