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
91176allure 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