Introducción
Que una API responda bien a un usuario no garantiza que aguante a muchos al mismo tiempo. Para eso existen las pruebas de carga: simulan usuarios simultáneos y miden tiempos de respuesta y errores.
En este artículo uso k6, una herramienta open source de Grafana Labs, para hacer una prueba de carga a una API REST en .NET 8. La prueba se ejecuta sola en GitHub Actions en cada cambio y el reporte se publica en la nube con GitHub Pages.
¿Por qué k6?
- Las pruebas se escriben en JavaScript, así que son fáciles de leer y versionar junto al código.
- Es un solo binario, rápido y liviano: corre sin problema dentro de un runner de CI.
- Permite definir thresholds (umbrales): si el rendimiento no cumple, k6 termina con error y el pipeline falla.
- Genera un dashboard web en HTML con gráficos de la ejecución.
La API y el repositorio público
La aplicación es Banco API, una Minimal API en .NET 8 con endpoints para listar, crear, depositar, retirar y eliminar cuentas bancarias (datos en memoria).
Repositorio público del equipo: github.com/viccarretero/banco-api-pruebas. Las pruebas funcionales de la misma API se hacen con Newman; eso lo explica mi compañero Victor Carretero en su artículo.
El script de carga
El archivo tests/k6/carga.js define cómo crece la carga y qué se considera aceptable:
export const options = {
stages: \[
{ duration: '30s', target: 20 }, // subida: de 0 a 20 usuarios
{ duration: '1m', target: 20 }, // carga sostenida: 20 usuarios
{ duration: '15s', target: 0 }, // bajada
],
thresholds: {
http\_req\_duration: \['p(95)<500'], // el 95 % de las peticiones en menos de 500 ms
http\_req\_failed: \['rate<0.01'], // menos del 1 % de errores
checks: \['rate>0.99'], // más del 99 % de validaciones correctas
},
};
Cada usuario virtual (VU) repite un flujo realista dividido en dos grupos: consultar cuentas y hacer operaciones. Con check se valida que cada respuesta sea correcta, no solo rápida:
group('Operaciones', () => {
const nueva = http.post(`${BASE\_URL}/api/cuentas`,
JSON.stringify({ titular: `Usuario ${\_\_VU}-${\_\_ITER}`, saldoInicial: 100 }), JSON\_HEADERS);
check(nueva, { 'crear: status 201': (r) => r.status === 201 });
const id = nueva.json('id');
const deposito = http.post(`${BASE\_URL}/api/cuentas/${id}/depositos`, JSON.stringify({ monto: 50 }), JSON\_HEADERS);
check(deposito, { 'depositar: saldo 150': (r) => r.json('saldo') === 150 });
const retiro = http.post(`${BASE\_URL}/api/cuentas/${id}/retiros`, JSON.stringify({ monto: 30 }), JSON\_HEADERS);
check(retiro, { 'retirar: saldo 120': (r) => r.json('saldo') === 120 });
});
sleep(1);
Así cada usuario crea su propia cuenta, deposita 50 y retira 30, y se comprueba que el saldo final sea exacto aunque haya 20 usuarios operando a la vez.
Automatización con GitHub Actions
En el workflow .github/workflows/pruebas-api.yml, el job de k6 levanta la API dentro del runner, instala k6 con la acción oficial de Grafana y ejecuta el script exportando el dashboard HTML:
- name: Instalar k6
uses: grafana/setup-k6-action@v1
- name: Ejecutar la prueba de carga
env:
BASE\_URL: http://localhost:5000
K6\_WEB\_DASHBOARD: 'true'
K6\_WEB\_DASHBOARD\_EXPORT: site/k6/index.html
run: |
mkdir -p site/k6
k6 run --summary-export=site/k6/resumen.json tests/k6/carga.js
El job de k6 corre en paralelo con el de Newman, y al final un último job publica ambos reportes en GitHub Pages.
Resultados y publicación en la nube
Reporte publicado: viccarretero.github.io/banco-api-pruebas/k6
En la primera ejecución (1 minuto 45 segundos de prueba):
| Métrica | Valor |
|---|---|
| Usuarios virtuales (máximo) | 20 |
| Peticiones HTTP | 8 315 (78,9 por segundo) |
| Iteraciones completas | 1 663 |
| Tiempo de respuesta promedio | 0,29 ms |
| Percentil 95 (p95) | 0,95 ms |
| Tiempo máximo | 23,1 ms |
| Peticiones fallidas | 0 % |
| Checks | 14 967 correctos, 0 fallidos |
Los tres thresholds se cumplieron con mucho margen: el p95 quedó en menos de 1 ms frente al límite de 500 ms. Es un resultado esperado para una API con datos en memoria; con una base de datos real los tiempos serían mayores, y ahí es donde la prueba de carga se vuelve más útil para detectar cuellos de botella.
Conclusiones
k6 permite tratar el rendimiento como un requisito más: se escribe en código, se versiona y se valida automáticamente en cada cambio. Gracias a los thresholds, si un cambio vuelve lenta la API, el pipeline lo detecta antes de publicar. Junto con las pruebas funcionales de Newman, el proyecto cubre las dos preguntas clave: si la API hace lo correcto y si lo sigue haciendo bajo carga.
Enlaces
- Repositorio: github.com/viccarretero/banco-api-pruebas
- Reportes en GitHub Pages: viccarretero.github.io/banco-api-pruebas
- Ejecución del pipeline: GitHub Actions
- Video: (pendiente)
- Artículo complementario sobre Newman (Victor Carretero): https://dev.to/viccarretero/pruebas-funcionales-de-una-api-net-con-newman-y-github-actions-33pm
- Documentación de k6
Gerald Zevallos — Calidad y Pruebas de Software, Universidad Privada de Tacna.
Top comments (0)