Aplicación de consola creada para practicar pruebas unitarias. El repositorio contiene el código fuente funcional pero los tests están incompletos — tu tarea es escribir las pruebas unitarias de cada clase de dominio.
- What you'll practice
- Tech Stack
- Getting Started
- Project Structure
- Usage
- Testing
- Configuration
- Architecture
- JUnit 5 (Jupiter) — escribir pruebas unitarias con asserts, excepciones esperadas y
@ParameterizedTest - Mockito 5 — aislar la capa de dominio mockeando dependencias con
@MockyMockito.mockStatic() - JaCoCo — medir cobertura del código y buscar líneas no cubiertas
| Technology | Version |
|---|---|
| Java | 17 |
| Spring Boot | 3.5.14 |
| Spring Shell | 3.4.2 |
| Gradle | 9.5.1 |
| Retrofit 2 + Gson | 2.x |
| JUnit 5 (Jupiter) | 5.12 |
| Mockito | 5.14.0 |
| JaCoCo | 0.8.15 |
- Java 17+
- Gradle 9.5.1 (wrapper incluido)
./gradlew bootJarGenera el jar en build/libs/unit-testing-app-1.0.0.jar.
java -jar build/libs/unit-testing-app-1.0.0.jarO ejecuta la clase App desde el IDE (paquete com.cedaniel200.practice).
Warning
El comando send requiere las variables de entorno EMAIL_USERNAME y EMAIL_PASSWORD configuradas. Sin ellas, el envío fallará con un mensaje de error. Consulta Configuration para más detalles.
- IntelliJ IDEA:
File → Openy selecciona el archivobuild.gradle— se abrirá como proyecto Gradle automáticamente - VS Code: abre la carpeta raíz con las extensiones Gradle y Java instaladas
src/main/java/com/cedaniel200/practice/
├── console/ # Comandos de consola (Spring Shell)
├── domain/ # Lógica de negocio — capa más interna, Java puro
│ ├── calculator/ # Calculadora (Strategy Pattern)
│ │ └── operation/ # Adder, Subtractor, Multiplier, Divider
│ ├── email/ # Envío de correos
│ ├── greeting/ # Saludos por idioma
│ ├── phrase/ # Frases
│ └── user/ # Usuarios (integración HTTP)
├── persistence/ # Acceso a datos (DAO)
├── repository/ # Abstracción de repositorios
└── service/ # Clientes HTTP (Retrofit a JSONPlaceholder)
La aplicación expone comandos interactivos via Spring Shell.
| Command | Description |
|---|---|
add --first-number <int> --second-number <int> |
Suma dos números enteros |
subtract --first-number <int> --second-number <int> |
Resta dos números enteros |
multiply --first-number <int> --second-number <int> |
Multiplica dos números enteros |
divide --dividend <int> --divider <int> |
Divide dos números enteros |
| Command | Description |
|---|---|
send --to <string> --subject <string> --message <string> |
Envía un correo electrónico |
| Command | Description |
|---|---|
greet --language <es|en|pt> |
Saludo en el idioma especificado |
User (consumen API https://jsonplaceholder.typicode.com)
| Command | Description |
|---|---|
find-by-id --id <int> |
Busca un usuario por ID |
list |
Lista todos los usuarios |
Tip
Para más detalles de cada comando ejecuta help <nombre> desde la consola. Por ejemplo: help add.
./gradlew unitTestEjecuta solo las pruebas unitarias (archivos *Test.java). Es el único comando necesario para el aprendizaje.
Para generar reporte de cobertura:
./gradlew unitTest jacocoUnitTestReportEl reporte se abre en build/reports/jacoco/jacocoUnitTestReport/html/index.html.
Escribe los tests para cada clase de dominio:
| Domain class | What to test |
|---|---|
AdderDefault |
Suma de enteros |
SubtractorDefault |
Resta de enteros |
MultiplierDefault |
Multiplicación de enteros |
DividerDefault |
División exacta, división por cero lanza ArithmeticException |
CalculatorDefault |
Cada operación delega correctamente en su strategy |
GreetingByLanguage |
es → "Hola", en → "Hello", pt → "Ola", otro → "unsupported language" |
GreetingDomainDefault |
Delegación a GreetingByLanguage |
EmailDomainDefault |
Comportamiento con EmailHandler mockeado |
EmailHandlerDefault |
Envío exitoso/fallido, contadores de enviados y no enviados |
PhraseDomainDefault |
Autor vacío → "anonymous", creación y obtención de frases |
UserDomainDefault |
ID válido (1-10), ID fuera de rango, MalformedDataException, ServiceNotAvailableException |
Note
La cobertura con JaCoCo excluye los paquetes config/, console/, model/ y la clase App, ya que el objetivo es medir solo la capa de dominio.
| Command | Description |
|---|---|
./gradlew e2eTest |
Pruebas end-to-end de consola (*E2E*.java) |
./gradlew integrationTest |
Pruebas de integración con servicios externos (*Integration*.java) |
./gradlew test |
Todas las pruebas |
./gradlew clean test jacocoTestReport |
Todas + reporte de cobertura global |
Warning
Las pruebas E2E e Integration consumen conexiones HTTP externas y no son necesarias para el aprendizaje de pruebas unitarias.
| Variable | Description |
|---|---|
EMAIL_USERNAME |
Correo Gmail para enviar |
EMAIL_PASSWORD |
App password de Gmail |
export EMAIL_USERNAME=micorreo@gmail.com
export EMAIL_PASSWORD=abcd1234efgh5678Si no se configuran, el comando send usará valores por defecto y fallará con un mensaje de error.
console/: Comandos de consola (Spring Shell). Punto de entrada para cada operación.domain/: Lógica y reglas de negocio. Capa más interna, sin dependencias de frameworks.persistence/: Implementación del patrón DAO para acceso a datos.repository/: Implementación del patrón Repository. Puede comunicarse con la capa de persistencia.service/: Clientes HTTP para comunicación con servicios en la nube (Retrofit).exception/: Capa transversal con excepciones técnicas y de negocio (MalformedDataException,ServiceNotAvailableException).model/: Capa transversal con clases del modelo de dominio.
- Strategy:
CalculatorDefaultcomponeAdder,Subtractor,Multiplier,Divider. - Interface + Impl Default: Separación interfaz/implementación en cada subdominio.
- Repository:
UserRepository+UserRepositoryDefault. - DAO:
PhraseDao. - DI por constructor: Via Spring (
@Configurationenconfig/).
MIT © Cesar Daniel
