- Project Overview
- Project Goal
- Architecture & Technologies:
- Requirements:
- Getting Started:
- Key Learning Outcomes
- Contributing
- Further Reading
- License
This project demonstrates why traditional code coverage tools aren't enough to ensure test quality and how mutation testing can reveal weaknesses in your test suite that JaCoCo and PMD might miss.
Built as an eCommerce cross-selling API using Spring Boot 3, this project showcases the implementation of effective mutation testing strategies using Pitest with the Descartes mutation engine.
This project uses Gradle. If your usual build tool is Maven, check out the analogous project: An example of effective mutation testing in Spring Boot 3 projects with Maven.
Implement an eCommerce system using Outside-In TDD approach while demonstrating that even with high code coverage (JaCoCo) and static analysis (PMD), your tests might not be as robust as you think.
Mutation testing reveals the truth about test quality.
- Java 21
- Spring Boot 3.5.5
- Spring Data JPA for data persistence
- PostgreSQL as the primary database
- Flyway for database migrations
- Testcontainers for integration testing
- JaCoCo - Traditional code coverage (shows what lines are executed)
- PMD - Static code analysis (finds potential bugs and code smells)
- PITest with Descartes - Mutation testing (reveals if your tests actually validate behavior)
- ArchUnit - to check that the rules for the layers of Hexagonal Architecture are respected
- Spotless - Code formatting
- MapStruct - Bean mapping
- Lombok - Boilerplate code reduction
- OpenAPI Generator - API documentation and client generation
- Swagger/OpenAPI - API documentation
-
GET /api/products
-
GET /api/products/{productId}
-
GET /api/users/{userId}/basket
-
POST /api/users/{userId}/basket
- GET /api/products
[
{
"id": 1,
"name": "Dell Latitude 3301 Intel Core i7-8565U/8GB/512GB SSD/13.3",
"price": "999,00 €"
},
{
"id": 2,
"name": "Samsonite Airglow Laptop Sleeve 13.3",
"price": "41,34 €"
},
{
"id": 3,
"name": "Logitech Wireless Mouse M185",
"price": "10,78 €"
},
{
"id": 4,
"name": "Fellowes Mouse Pad Black",
"price": "1,34 €"
}
]
- GET /api/products/{productId}
{
"product": {
"id": 1,
"name": "Dell Latitude 3301 Intel Core i7-8565U/8GB/512GB SSD/13.3",
"price": "999,00 €"
},
"cross_selling": [
{
"id": 2,
"name": "Samsonite Airglow Laptop Sleeve 13.3",
"price": "41,34 €"
},
{
"id": 3,
"name": "Logitech Wireless Mouse M185",
"price": "10,78 €"
}
]
}
- GET /api/users/{userId}/basket
{
"id": 1,
"userId": 1,
"items": {
"products": [
{
"id": 3,
"name": "Logitech Wireless Mouse M185",
"price": "10,78 €"
}
]
}
}
- POST /api/users/{userId}/basket
{
"id": 3,
"name": "Logitech Wireless Mouse M185",
"price": "10,78 €"
}
8. When we add a product to a basket and the basket does not exist, it is created automatically and the product is added successfully.
12. This is the example of the table creations.
- Test Coverage: Minimum 80% line coverage
- Mutation Coverage: Minimum 80% mutation score
- Static Analysis: Zero PMD violations
- Code Style: Consistent formatting enforced by Spotless
- Architecture: Implement a hexagonal architecture with proper layer separation
- Java 21 or higher
- Docker (for PostgreSQL and Testcontainers)
- Gradle 8.x (wrapper included)
./gradlew clean build
./gradlew test
./gradlew jacocoTestReport
open build/reports/jacoco/html/index.html
./gradlew spotlessCheck
./gradlew pmdMain
./gradlew pitest
open build/reports/pitest/index.html
docker build -t mutation-testing-with-gradle .
docker run -d -p 8080:8080 --name mutation-testing-with-gradle mutation-testing-with-gradle
docker compose up -d
URL to access to Swagger UI
docker compose down -v
By exploring this project, you'll understand:
- Why 100% code coverage can be misleading
- How mutation testing reveals test weaknesses that traditional metrics miss
- The difference between testing code execution vs. testing behavior
- Practical strategies for writing more effective tests
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Write tests first (TDD approach)
- Ensure all quality gates pass (
./gradlew check
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
- Minimum 80% line coverage (JaCoCo)
- Minimum 80% mutation coverage (PITest)
- All PMD rules must pass
- All tests must be green
This project is licensed under the MIT License - see the LICENSE file for details.
⭐ If this project helped you understand mutation testing better, please give it a star!
Code coverage tells you what code your tests execute. Mutation testing tells you if your tests actually validate anything meaningful.