Skip to content

Commit e2174e9

Browse files
authored
Revise README for clarity and project details
Updated project description and structure details in README.
1 parent 0009595 commit e2174e9

1 file changed

Lines changed: 176 additions & 95 deletions

File tree

README.md

Lines changed: 176 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,168 @@
1-
# REST Assured API Testing — Suite de Automatización
1+
# REST Assured API Testing Framework
22

3-
> Proyecto de automatización de pruebas de API construido con Java, RestAssured y TestNG,
4-
> con pipeline CI/CD en GitHub Actions y reportes Allure publicados automáticamente.
3+
> Proyecto personal de automatización de pruebas de API construido mientras aprendía QA Automation.
4+
> Incluye 4 APIs, 8 suites de prueba organizadas por propósito, pipeline CI/CD con GitHub Actions
5+
> y reportes Allure publicados automáticamente en GitHub Pages.
56
6-
🔗 **[Ver reporte Allure en vivo](https://ipanaque94.github.io/RestAssured3APIS)**
7+
**[Ver reporte Allure en vivo](https://ipanaque94.github.io/RestAssured3APIS)**
78

89
---
910

10-
## ¿Por qué existe este proyecto?
11+
## Por qué construí esto
1112

12-
Cuando empecé a aprender QA Automation me di cuenta de que la mayoría de los proyectos
13-
de práctica prueban una sola API con 5 tests. Quería construir algo más cercano a lo que
14-
se hace en una empresa real: múltiples APIs, suites organizadas por propósito, pipeline
15-
CI/CD que corre automáticamente y reportes que cualquier stakeholder pueda leer sin
16-
entrar al código.
13+
Cuando empecé a estudiar QA Automation me di cuenta de que la mayoría de proyectos de práctica
14+
consisten en 5 o 6 tests contra una sola API sin ninguna organización real. Quería entender
15+
cómo trabaja un QA en una empresa de verdad, así que me propuse construir algo con la estructura
16+
que tendría un proyecto profesional.
1717

18-
Este proyecto prueba **4 APIs distintas** (REST y SOAP), tiene **8 suites independientes**
19-
y un pipeline que publica el reporte consolidado en GitHub Pages en cada push.
18+
El proceso no fue lineal. Hubo errores que me tomaron días resolver: tokens que se agotaban
19+
porque el `@BeforeClass` corría más veces de las necesarias, tests que pasaban en CI pero
20+
fallaban en local porque una API bloqueaba mi IP, specs que llegaban nulos a los tests por
21+
el orden de ejecución de TestNG. Cada uno de esos errores me enseñó algo que no aparece en
22+
ningún tutorial.
2023

2124
---
2225

23-
## ¿Qué se prueba y por qué?
26+
## Qué se prueba y por qué elegí cada API
2427

25-
| API | Protocolo | ¿Qué valida? |
28+
| API | Tipo | Por qué la elegí |
2629
|---|---|---|
27-
| [Simple Books API](https://simple-books-api.glitch.me) | REST + Auth | Flujo completo con autenticación, CRUD de órdenes, validación de schema JSON |
28-
| [Rick and Morty API](https://rickandmortyapi.com) | REST público | Validación de campos simples y anidados con JsonPath |
29-
| [JSONPlaceholder](https://jsonplaceholder.typicode.com) | REST público | Operaciones CRUD: GET, POST, PUT, DELETE |
30-
| [DataAccess](https://www.dataaccess.com) | SOAP/XML | Consumo de servicio SOAP con validación de respuesta XML |
31-
32-
La elección de estas APIs no fue casual. Simple Books tiene autenticación real con tokens,
33-
lo que permitió cubrir seguridad, manejo de errores y flujos autenticados. JSONPlaceholder
34-
cubre las operaciones HTTP básicas. SOAP está presente porque muchas empresas todavía
35-
tienen servicios legacy con ese protocolo.
30+
| Simple Books API | REST + Auth | Es la única con autenticación real con tokens, lo que permite cubrir seguridad, flujos autenticados y manejo de errores de autorización |
31+
| Rick and Morty API | REST público | Tiene respuestas con objetos anidados, ideal para practicar JsonPath en campos como `location.name` y `origin.url` |
32+
| JSONPlaceholder | REST público | API simple y estable, perfecta para cubrir el ciclo completo: GET, POST, PUT, DELETE sin complicaciones de autenticación |
33+
| DataAccess | SOAP/XML | Muchas empresas todavía tienen servicios legacy con SOAP. Quería entender cómo difiere de REST en headers, body y manejo de respuesta |
3634

3735
---
3836

39-
## Stack técnico
37+
## Análisis de casos de prueba por suite
4038

41-
| Herramienta | Versión | Uso |
42-
|---|---|---|
43-
| Java | 17 | Lenguaje base |
44-
| RestAssured | 5.3.1 | Cliente HTTP para pruebas de API |
45-
| TestNG | 7.10.2 | Framework de pruebas con soporte de grupos y DataProviders |
46-
| Allure | 2.25.0 | Reportes interactivos con trazabilidad completa |
47-
| Jackson | 2.17.1 | Serialización/deserialización de objetos Java ↔ JSON |
48-
| Gradle | 9.1.0 | Build y gestión de dependencias |
49-
| GitHub Actions || CI/CD con jobs independientes por suite |
39+
Aquí está el razonamiento detrás de cada suite. El código sin esta explicación es solo
40+
sintaxis; lo importante es el **por qué** de cada decisión de prueba.
41+
42+
### Smoke — "¿El sistema responde?"
43+
44+
El propósito del Smoke no es encontrar bugs profundos sino confirmar que después de un
45+
deploy el sistema está vivo. Por eso solo incluye el test más representativo de cada API.
46+
47+
Criterio de diseño: si el Smoke falla, no tiene sentido correr el resto. Por eso en el
48+
pipeline CI los demás jobs dependen de que Smoke termine.
49+
50+
### Regression — "¿Sigue funcionando todo lo que funcionaba antes?"
51+
52+
Aquí están los tests de funcionalidad completa. Incluye el `DataProvider` que prueba
53+
libros con IDs 1, 2 y 3 en una sola definición de test. La lógica detrás es la técnica
54+
de partición de equivalencia del ISTQB: si el libro con ID 1 pasa, hay alta probabilidad
55+
de que el de ID 2 también, pero vale la pena verificarlo explícitamente porque cada ID
56+
podría tener datos diferentes en el servidor.
57+
58+
### Contract — "¿La estructura de la respuesta cambió sin avisarnos?"
59+
60+
Este es uno de los tests más valiosos y menos obvios cuando empiezas en QA. Cuando una
61+
API cambia el nombre de un campo o agrega campos obligatorios, tus tests funcionales
62+
podrían seguir pasando si no validas la estructura completa.
63+
64+
La validación con JSON Schema captura exactamente eso: si el equipo de backend cambia
65+
`"id"` por `"bookId"` en la respuesta, el test de Contract lo detecta aunque el GET
66+
siga devolviendo 200.
67+
68+
### Security — "¿El sistema protege correctamente sus recursos?"
69+
70+
Probé tres escenarios distintos:
71+
- Token completamente inválido (`Bearer TokenInvalido`) → debe dar 401
72+
- Request sin token → debe dar 401
73+
- Token válido pero con cuerpo incorrecto → debe dar 400, no 401
74+
75+
La distinción entre 401 y 403 también importa: 401 significa que no estás autenticado,
76+
403 significa que estás autenticado pero no tienes permisos. Confundirlos en una
77+
implementación es un bug de seguridad real.
78+
79+
### Negative — "¿Qué pasa cuando el usuario hace algo que no debería?"
80+
81+
Los tests negativos son los que los desarrolladores menos prueban y los que más revelan
82+
sobre la calidad real de un sistema. Cubrí:
83+
84+
- Cuerpo vacío en POST `/orders` → ¿Da 400 con mensaje descriptivo o da 500 genérico?
85+
- Libro con ID inexistente (999) → ¿Da 404 o da 200 con body vacío?
86+
- Campos obligatorios faltantes en `/api-clients` → ¿El mensaje de error identifica
87+
cuál campo falta?
88+
89+
Este último punto es importante: un API bien diseñada no dice solo "error 400", sino
90+
"Invalid or missing client email". Eso le permite al cliente de la API saber exactamente
91+
qué corregir.
92+
93+
### Idempotencia — "¿Los métodos HTTP se comportan como el protocolo dice?"
94+
95+
Esta suite surgió de estudiar el protocolo HTTP. Según la especificación, PATCH y DELETE
96+
son idempotentes: ejecutarlos múltiples veces con los mismos datos debe producir el mismo
97+
resultado que ejecutarlos una vez.
98+
99+
Verifiqué dos casos:
100+
- PATCH dos veces con el mismo body → ambas respuestas deben ser 204
101+
- DELETE dos veces → primera debe ser 204, segunda debe ser 404
102+
103+
El segundo caso es especialmente importante: si el segundo DELETE devolviera 204 también
104+
(como si la orden todavía existiera), indicaría un problema en la lógica del servidor.
105+
106+
### Performance — "¿El sistema responde en tiempo razonable?"
107+
108+
Aunque una prueba de rendimiento real requiere JMeter o k6 con carga concurrente, agregar
109+
una validación de tiempo de respuesta en los tests de API tiene valor: detecta degradaciones
110+
obvias y establece un contrato de SLA mínimo documentado en el código.
111+
112+
El umbral de 2000ms es conservador para una API pública. En un proyecto real, este número
113+
vendría del SLA acordado con el equipo de producto.
114+
115+
### SOAP — "¿Los servicios legacy responden correctamente?"
116+
117+
SOAP fue el estándar de integración entre sistemas durante 15 años. Aunque REST lo reemplazó
118+
en la mayoría de sistemas nuevos, muchas empresas de banca, seguros y gobierno todavía
119+
los usan. Probé la conversión de números a palabras porque es un caso de uso simple que
120+
permite concentrarse en entender las diferencias del protocolo sin complejidad de negocio.
50121

51122
---
52123

53-
## Suites de prueba
124+
## Decisiones técnicas que aprendí en el proceso
54125

55-
Cada suite tiene un propósito claro y corre de forma independiente:
126+
**Por qué `Config.java` lee en ese orden: env var → system property → properties file**
56127

57-
| Suite | Propósito | Qué valida |
58-
|---|---|---|
59-
| 🔥 **Smoke** | Verificación rápida post-deploy | El sistema responde y los flujos críticos funcionan |
60-
| 🔁 **Regression** | Cobertura funcional completa | Que nada se rompió con los últimos cambios |
61-
| 📋 **Contract** | Validación de esquema JSON | La estructura de la respuesta no cambió sin aviso |
62-
| 🔒 **Security** | Autenticación y autorización | Tokens inválidos retornan 401, acceso correcto retorna 200 |
63-
|**Negative** | Manejo de errores | El sistema responde correctamente ante datos inválidos |
64-
| 🔄 **Idempotencia** | Métodos HTTP idempotentes | PATCH repetido = mismo resultado, DELETE repetido = 404 |
65-
|**Performance** | Tiempos de respuesta | El endpoint responde en menos de 2000ms |
66-
| 🧼 **SOAP** | Servicios legacy XML | El servicio SOAP convierte números a palabras correctamente |
128+
Esto permite que el mismo código corra en tres contextos sin cambios:
129+
en local lee del `config.properties`, en CI lee de las variables de entorno inyectadas
130+
como secrets, y si alguien necesita sobreescribir temporalmente usa `-Dproperty=value`.
131+
132+
**Por qué hay una clase base por API en lugar de configurar todo en cada test**
133+
134+
Si la URL de una API cambia, se modifica en un solo lugar. Si el header de autenticación
135+
cambia, se modifica en un solo lugar. Los tests hijos se concentran solo en la lógica
136+
de prueba, no en la configuración.
137+
138+
**Por qué `@BeforeClass(alwaysRun = true)` en las clases base**
139+
140+
Sin `alwaysRun = true`, cuando TestNG ejecuta una suite que filtra por grupos, se salta
141+
el `@BeforeClass` porque técnicamente "no pertenece al grupo". El resultado es que `spec`
142+
llega nulo a los tests y falla con un error confuso de "Specification to merge cannot be null".
143+
Fue uno de los errores que más tiempo me tomó entender.
144+
145+
**Por qué un XML por suite en lugar de un solo XML con grupos**
146+
147+
Permite que el CI lance jobs completamente independientes con un solo parámetro
148+
(`-Dsuite=Smoke`) y que cada job suba sus propios resultados de Allure como artefacto
149+
para el reporte consolidado final.
67150

68151
---
69152

70153
## Cómo ejecutar
71154

72-
**Requisitos:** Java 17, Gradle 9+
155+
Requisitos: Java 17, Gradle 9+
73156

74157
```bash
75-
# Todas las suites
158+
# Clonar el repositorio
159+
git clone https://github.com/ipanaque94/RestAssured3APIS.git
160+
cd RestAssured3APIS
161+
162+
# Ejecutar todas las suites
76163
./gradlew clean test
77164

78-
# Suite específica
165+
# Ejecutar una suite específica
79166
./gradlew clean test -Dsuite=Smoke
80167
./gradlew clean test -Dsuite=Regression
81168
./gradlew clean test -Dsuite=Security
@@ -84,77 +171,71 @@ Cada suite tiene un propósito claro y corre de forma independiente:
84171
./gradlew clean test -Dsuite=Idempotencia
85172
./gradlew clean test -Dsuite=Performance
86173
./gradlew clean test -Dsuite=SOAP
87-
```
88174

89-
**Ver el reporte Allure localmente:**
90-
```bash
175+
# Ver reporte Allure localmente
91176
allure serve build/allure-results
92177
```
93178

94179
---
95180

96181
## Pipeline CI/CD
97182

98-
El pipeline corre automáticamente en cada push a `main`. Los jobs tienen dependencias
99-
para que Smoke sea el primer gate — si falla, los demás no corren innecesariamente:
183+
GitHub Actions corre automáticamente en cada push a `main`. Los jobs tienen dependencias
184+
para que Smoke funcione como gate de calidad:
100185

101186
```
102-
Push → 🔥 Smoke
103-
├── 🔁 Regression ──→ 🔄 Idempotencia
104-
│ └──→ ⚡ Performance
105-
├── 📋 Contract
106-
├── 🔒 Security
107-
├── ❌ Negative
108-
└── 🧼 SOAP
109-
└── 📊 Reporte consolidado → GitHub Pages
187+
Push a main
188+
|
189+
v
190+
Smoke (si falla, los demás no se bloquean gracias a always())
191+
|
192+
+---> Regression ---> Idempotencia
193+
| \---> Performance
194+
+---> Contract
195+
+---> Security
196+
+---> Negative
197+
+---> SOAP
198+
|
199+
v
200+
Reporte Consolidado → GitHub Pages (publicado automáticamente)
110201
```
111202

112-
Cada job publica sus resultados como artefacto. Al final, el job `publish-report`
113-
descarga todos los resultados, genera un reporte Allure consolidado y lo publica
114-
automáticamente en GitHub Pages.
203+
Las URLs de las APIs se configuran como secrets en GitHub para no exponerlas en el código.
115204

116205
---
117206

118-
## Decisiones de diseño
119-
120-
Estas decisiones las tomé pensando en mantenibilidad y escalabilidad — no solo en
121-
hacer que los tests pasen:
122-
123-
**Clase base por API (`BaseBooksTest`, `BaseRickMorty`, etc.)**
124-
Cada API tiene su propia clase base con la configuración de URL y el `RequestSpec`.
125-
Si cambia la URL de una API, se modifica en un solo lugar.
126-
127-
**`Config.java` con prioridad de configuración**
128-
Lee la URL en este orden: variable de entorno → system property → `config.properties`.
129-
Esto permite que CI inyecte URLs distintas por ambiente sin tocar el código.
130-
131-
**`@BeforeClass(alwaysRun = true)` con flag `initialized`**
132-
TestNG crea una nueva instancia de la clase por cada suite que la incluye. Sin el flag
133-
`static initialized`, el setup se ejecutaría múltiples veces y agotaría el rate limit
134-
de la API al obtener el token.
207+
## Stack
135208

136-
**Un XML por suite en lugar de grupos en un solo XML**
137-
Permite correr cada suite con un comando simple (`-Dsuite=Smoke`) y que el CI lance
138-
jobs completamente independientes sin configuración adicional.
209+
| Herramienta | Versión | Uso |
210+
|---|---|---|
211+
| Java | 17 | Lenguaje base |
212+
| Rest Assured | 5.3.1 | Cliente HTTP para pruebas de API |
213+
| TestNG | 7.10.2 | Test runner con grupos, DataProviders y dependencias entre tests |
214+
| Allure | 2.25.0 | Reportes con severidad, descripción y trazabilidad por test |
215+
| Jackson | 2.17.1 | Serialización de objetos Java a JSON y deserialización de respuestas |
216+
| Gradle | 9.1.0 | Build y gestión de dependencias |
217+
| GitHub Actions || CI/CD con jobs independientes por suite |
139218

140219
---
141220

142-
## Qué aprendí construyendo esto
221+
## Lo que todavía quiero mejorar
143222

144-
Más allá del código, este proyecto me enseñó cosas que no están en los tutoriales:
223+
Ser honesto sobre lo que falta es parte de aprender:
145224

146-
- El `@BeforeClass` sin `alwaysRun = true` se salta cuando TestNG corre grupos específicos,
147-
dejando el `spec` nulo y fallando con un error confuso de "Specification cannot be null"
148-
- Los headers duplicados entre el `spec` y el `given()` pueden causar errores 400
149-
silenciosos en algunas APIs
225+
- Agregar tests de integración que encadenen múltiples endpoints (crear orden → verificar
226+
que aparece en GET /orders → eliminarla → verificar que da 404)
227+
- Implementar retry automático en tests que dependen de APIs con rate limiting
228+
- Agregar validación de headers de respuesta, no solo del body
229+
- Cubrir paginación en la Rick and Morty API
150230

151231
---
152232

153233
## Autor
154234

155-
**Enoc Ipanaque**
156-
[LinkedIn](www.linkedin.com/in/enoc-isaac-ipanaque-rodas-b3729a283) · [GitHub](https://github.com/ipanaque94)
235+
**Enoc Ipanaque** — Lima, Perú
236+
237+
QA Automation Engineer en formación. Este proyecto lo construí mientras completaba el
238+
curso de REST Assured Avanzado de [Free Range Testers](https://www.freerangetesters.com)
239+
y preparaba la certificación ISTQB Foundation Level.
157240

158-
Estudiante de QA Automation en proceso de certificación ISTQB CTFL.
159-
Construido sobre los conocimientos del curso **REST Assured Avanzado**
160-
de [Free Range Testers](https://www.freerangetesters.com).
241+
[LinkedIn](https://www.linkedin.com/in/enoc-isaac-ipanaque-rodas-b3729a283) · [GitHub](https://github.com/ipanaque94)

0 commit comments

Comments
 (0)