Application to manage Fantasy Sport games, enabling the users to search players, pick their squads and participate in championships.
This document is also available in 🇧🇷 Portuguese.
This application is for educational purposes and the goal is to show good practices of software architecture and testing.
This project is written using the JDK 15 Platform, Spring Boot with the reactive web framework Spring WebFlux and MongoDB as the database.
This application uses the Hexagonal Architecture as the architectural style.
Following this, the application modules are split in three parts:
-
Business Logic (Core): Code that contains pure business logic, with minimal coupling to frameworks, databases or messaging systems. Whenever the application needs to communicate with the external world, the core should depend on an interface that is implemented by a secondary adapter.
-
Primary adapters: Code that drives the application. The primary adapters should depend on primary ports defined on the business logic.
-
Secondary adapters: Code that enables the application to talk to external world. Secondary adapters should implement secondary ports defined in the application core.
The project is split into modules according to business use cases. Each module
has its own package inside the root package io.henriquels25.fantasysport
.
Example:
The module responsible for managing the players is io.henriquels25.fantasysport.player
.
Inside a module, the code related to the business logic (core) is put in the root of the package.
Example:
The PlayerFacade
is the entry point for the application core for the Player Module and it
is placed on io.henriquels25.fantasysport.player
.
The adapters are placed in the package called infra
inside the module.
Example:
The adapters for the player module are placed on io.henriquels25.fantasysport.player.infra
.
The adapters are placed on packages according to their types. Controllers are put on the
package **.infra.controller
, adapters to Mongo documents on **.infra.mongo
, etc.
Primary adapters should depend on an entry point (primary port) to the module business logic (core).
Example:
The primary adapter PlayerController
depends on the PlayerOperations
(entry point to the business logic).
Secondary adapters should implement output ports that are defined in the module business logic (core).
Example:
The secondary adapter MongoPlayerRepository
implements the secondary port PlayerRepository
.
This project has three levels of testing:
-
Unit test: Cover the business logic of the modules. They are extremely fast and do not depend on any framework (other than JUnit5/Mockito), database or messaging system.
-
Integration test: Cover the adapters of the modules (everything inside the
infra
package). These tests are slower than unit tests as it is needed an application context, a database or other technologies. Usually, annotation like@WebFluxTest
,@DataMongoTest
and others are used. -
Acceptance test: This kind of test configure the whole application with the external dependencies (Database, Messaging Systems, External APIs) locally and the tests are written from the client perspective, as use cases. Usually, the annotation
@SpringBootTest
is used for this kind of test.
For code coverage purposes, only the unit and integration tests should be considered.
In order to have separate Gradle tasks for each kind of test, the following annotations should be used when defining tests:
- Unit Test:
@Test
(org.junit.jupiter.api.Test) - Integration Test:
@IntegrationTest
(io.henriquels25.fantasysport.annotations.IntegrationTest) - Acceptance test:
@AcceptanceTest
(io.henriquels25.fantasysport.annotations.AcceptanceTest)
The following Gradle tasks are available to run the tests:
- Unit Test:
./gradlew unitTest
- Integration Test:
./gradlew integrationTest
- Acceptance test:
./gradlew acceptanceTest
The JaCoCo Plugin is configured in the project to enable code coverage analysis.
The command ./gradlew jacocoTestReport
will generate HTML/XML code coverage reports of the executed tests.
The reports are available at the directory build/reports/jacoco
.
For example, in order to view the coverage from the unit and integration tests combined, the following commands should be executed:
./gradlew unitTest
./gradlew integrationTest
./gradlew jacocoTestReport
This project is available on Sonarcloud.
This repository uses GitHub Actions to automate the CI/CD pipeline.
Currently, the pipeline executes for pushes in every branch, executing the following steps:
- Unit tests
- Integration tests
- Coverage report and Sonar analysis
- Acceptance Tests