DEV Community

Cover image for Pruebas de carga con Artillery para APIs: Guía práctica
Roobia
Roobia

Posted on • Originally published at apidog.com

Pruebas de carga con Artillery para APIs: Guía práctica

Artillery es un kit de pruebas de carga open source basado en Node.js. Te permite generar tráfico concurrente contra una API desde un script YAML: defines fases de carga, describes el flujo de solicitudes, ejecutas artillery run script.yml y revisas percentiles de latencia, tasa de solicitudes y errores. En esta guía vas a instalar Artillery v2, crear una prueba real, ejecutarla, exportar resultados en el formato actual de v2 e integrarla en CI.

Prueba Apidog hoy

Qué es Artillery y cuándo usarlo

Artillery genera usuarios virtuales (VUs) que ejecutan escenarios contra tus endpoints. Cada VU actúa como un cliente simulado: realiza una solicitud, espera la respuesta y continúa con el siguiente paso del flujo.

Úsalo cuando necesites responder preguntas de rendimiento como:

  • ¿Cómo cambia la latencia p95 con 50 solicitudes por segundo?
  • ¿A partir de qué tasa de llegada empiezan los errores?
  • ¿La API se mantiene estable durante 5 minutos de carga sostenida?
  • ¿El sistema se degrada después de cierto volumen de usuarios concurrentes?

Artillery encaja bien cuando quieres pruebas declarativas. En lugar de programar manualmente bucles de concurrencia, describes la carga en YAML. Como corre sobre Node.js, puedes usar el mismo script en local, staging y CI.

Si estás comparando herramientas, revisa el resumen de las principales herramientas de prueba de carga y esta comparación de software de prueba de carga, donde se analizan alternativas como k6, JMeter y Gatling.

Instalar Artillery v2

El paquete npm se llama artillery. Instálalo globalmente y verifica la versión:

npm install -g artillery@latest
artillery version
Enter fullscreen mode Exit fullscreen mode

Necesitas una versión LTS reciente de Node.js. Artillery funciona en Windows, macOS y Linux.

Si prefieres no instalarlo globalmente, ejecútalo con npx:

npx artillery@latest run script.yml
Enter fullscreen mode Exit fullscreen mode

Crear un script de prueba con Artillery

Una prueba de Artillery es un archivo YAML con dos secciones principales:

  • config: define el objetivo, fases de carga, variables y configuración general.
  • scenarios: define lo que hace cada usuario virtual.

Crea un archivo script.yml:

config:
  target: "https://api.example.com"
  phases:
    - name: "Warm up"
      duration: 60
      arrivalRate: 5
    - name: "Ramp to peak"
      duration: 120
      arrivalRate: 5
      rampTo: 50
    - name: "Sustained load"
      duration: 300
      arrivalRate: 50
      maxVusers: 500
  variables:
    productId:
      - "1001"
      - "1002"

scenarios:
  - name: "Browse and create order"
    flow:
      - get:
          url: "/v1/products/{{ productId }}"
      - post:
          url: "/v1/orders"
          json:
            productId: "{{ productId }}"
            quantity: 2
Enter fullscreen mode Exit fullscreen mode

Este script hace tres cosas:

  1. Ejecuta un calentamiento con 5 VUs nuevos por segundo.
  2. Aumenta gradualmente hasta 50 VUs nuevos por segundo.
  3. Mantiene esa carga durante 5 minutos.

Cada usuario virtual consulta un producto y luego crea una orden.

Entender la sección config

config.target es el host base. Cada url dentro de los escenarios se concatena con este valor.

config:
  target: "https://api.example.com"
Enter fullscreen mode Exit fullscreen mode

Si un paso usa:

url: "/v1/products/1001"
Enter fullscreen mode Exit fullscreen mode

Artillery ejecutará la solicitud contra:

https://api.example.com/v1/products/1001
Enter fullscreen mode Exit fullscreen mode

Fases de carga

config.phases define cómo evoluciona la carga durante la prueba.

Las opciones más comunes son:

  • duration: duración de la fase, en segundos o como string legible, por ejemplo "5m".
  • arrivalRate: cantidad de nuevos usuarios virtuales que comienzan por segundo.
  • rampTo: aumenta linealmente desde arrivalRate hasta este valor.
  • arrivalCount: número fijo de VUs distribuidos durante la fase.
  • maxVusers: límite máximo de usuarios virtuales concurrentes.
  • name: etiqueta descriptiva para la salida.

Ejemplo:

phases:
  - name: "Ramp to peak"
    duration: 120
    arrivalRate: 5
    rampTo: 50
Enter fullscreen mode Exit fullscreen mode

Ten en cuenta un detalle importante: duration controla cuánto tiempo Artillery sigue creando nuevos usuarios virtuales. No siempre equivale al tiempo total de ejecución. Si un VU empieza cerca del final de una fase y su escenario tarda varios segundos, la prueba continúa hasta que ese VU termine.

Entender la sección scenarios

scenarios es una lista de flujos posibles. Cada escenario contiene un flow, que es la secuencia de pasos ejecutada por cada VU.

scenarios:
  - name: "Browse and create order"
    flow:
      - get:
          url: "/v1/products/{{ productId }}"
      - post:
          url: "/v1/orders"
          json:
            productId: "{{ productId }}"
            quantity: 2
Enter fullscreen mode Exit fullscreen mode

Los pasos usan verbos HTTP:

  • get
  • post
  • put
  • delete
  • patch

Para enviar JSON en una solicitud, usa json:

- post:
    url: "/v1/orders"
    json:
      productId: "{{ productId }}"
      quantity: 2
Enter fullscreen mode Exit fullscreen mode

La sintaxis {{ productId }} toma el valor desde variables, payload u otras fuentes compatibles.

También puedes definir varios escenarios y asignar pesos:

scenarios:
  - name: "Browse products"
    weight: 80
    flow:
      - get:
          url: "/v1/products"

  - name: "Create order"
    weight: 20
    flow:
      - post:
          url: "/v1/orders"
          json:
            productId: "1001"
            quantity: 1
Enter fullscreen mode Exit fullscreen mode

En este caso, Artillery elegirá el primer escenario con más frecuencia que el segundo.

Usar datos desde un CSV

Para pruebas realistas, evita quemar credenciales o IDs directamente en el YAML. Usa config.payload para cargar datos desde un CSV.

Ejemplo de users.csv:

email,password
user1@example.com,password123
user2@example.com,password456
Enter fullscreen mode Exit fullscreen mode

Script:

config:
  target: "https://api.example.com"
  payload:
    path: "./users.csv"
    fields:
      - "email"
      - "password"
  phases:
    - duration: 120
      arrivalRate: 20

scenarios:
  - name: "Login"
    flow:
      - post:
          url: "/login"
          json:
            email: "{{ email }}"
            password: "{{ password }}"
Enter fullscreen mode Exit fullscreen mode

Cada usuario virtual toma una fila del CSV y expone sus columnas como variables.

Ejecutar la prueba

Ejecuta el script con:

artillery run script.yml
Enter fullscreen mode Exit fullscreen mode

También puedes sobrescribir el target sin editar el archivo:

artillery run --target https://staging.example.com script.yml
Enter fullscreen mode Exit fullscreen mode

O pasar variables desde la línea de comandos:

artillery run -v '{ "productId": ["1001","1002"] }' script.yml
Enter fullscreen mode Exit fullscreen mode

Banderas útiles:

# Cambiar target
artillery run --target https://staging.example.com script.yml

# Seleccionar entorno definido en config.environments
artillery run --environment staging script.yml

# Cargar configuración desde otro archivo
artillery run --config config.yml script.yml

# Omitir verificación TLS en entornos de prueba con certificados autofirmados
artillery run --insecure script.yml
Enter fullscreen mode Exit fullscreen mode

Leer los resultados

Durante la ejecución, Artillery imprime métricas agregadas aproximadamente cada 10 segundos. Al finalizar, muestra un resumen.

Concéntrate en estas métricas:

  • Tasa de solicitudes: cuántas solicitudes por segundo logró ejecutar realmente la prueba.
  • Latencia p50: mediana del tiempo de respuesta.
  • Latencia p95: tiempo bajo el cual cae el 95% de las respuestas.
  • Latencia p99: muestra el comportamiento de cola más extremo.
  • Errores: timeouts, respuestas no exitosas y fallos agrupados por tipo.

No te quedes solo con el promedio. Una media aceptable puede ocultar un p95 o p99 alto. Si los errores aparecen durante la fase sostenida, probablemente encontraste un punto de saturación.

Para profundizar en qué métricas seguir, consulta esta guía de pruebas de rendimiento de API.

Generar resultados en Artillery v2

La generación de informes cambió en Artillery v2.

Muchos tutoriales antiguos recomiendan:

artillery run --output report.json script.yml
artillery report report.json
Enter fullscreen mode Exit fullscreen mode

La primera parte sigue funcionando. La segunda no.

El comando artillery report, que generaba HTML desde JSON, fue eliminado de la CLI de Artillery. La documentación oficial indica que ya no es compatible y no hay planes de recuperarlo.

Para exportar resultados JSON:

artillery run --output report.json script.yml
Enter fullscreen mode Exit fullscreen mode

Luego tienes tres opciones prácticas.

Opción 1: analizar el JSON con jq

Esto es útil en CI para validar umbrales.

Por ejemplo, para leer el p95 agregado:

jq '.aggregate.summaries["http.response_time"].p95' report.json
Enter fullscreen mode Exit fullscreen mode

Puedes usarlo para fallar el pipeline si la latencia supera tu presupuesto:

P95=$(jq '.aggregate.summaries["http.response_time"].p95' report.json)

if (( $(echo "$P95 > 500" | bc -l) )); then
  echo "p95 demasiado alto: ${P95}ms"
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

Opción 2: usar Artillery Cloud

Artillery Cloud es el reemplazo oficial para visualizar resultados en un panel alojado.

artillery run --record --key $ARTILLERY_CLOUD_API_KEY script.yml
Enter fullscreen mode Exit fullscreen mode

Opción 3: enviar métricas a tu stack de observabilidad

Si ya usas dashboards internos, puedes publicar métricas con el plugin publish-metrics u OpenTelemetry. Así puedes ver latencia, errores y throughput junto a las métricas de producción.

Ejecutar Artillery en CI

Artillery se integra fácilmente en CI porque es una CLI de Node.js.

Este workflow de GitHub Actions instala Artillery, ejecuta la prueba y sube report.json como artefacto:

name: Load test

on: [workflow_dispatch]

jobs:
  artillery:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "lts/*"

      - run: npm install -g artillery@latest

      - run: artillery run --output report.json script.yml

      - uses: actions/upload-artifact@v4
        with:
          name: artillery-report
          path: report.json
Enter fullscreen mode Exit fullscreen mode

Este ejemplo se ejecuta manualmente con workflow_dispatch. Es una buena práctica para pruebas de carga pesadas, porque consumen tiempo, tráfico real y recursos del entorno.

Si quieres convertirlo en una compuerta de calidad, añade un paso con jq:

      - name: Check p95 latency
        run: |
          P95=$(jq '.aggregate.summaries["http.response_time"].p95' report.json)
          echo "p95: $P95 ms"

          if (( $(echo "$P95 > 500" | bc -l) )); then
            echo "p95 supera el límite permitido"
            exit 1
          fi
Enter fullscreen mode Exit fullscreen mode

Dónde encaja Apidog: pruebas funcionales y control de CI

Artillery responde esta pregunta:

¿La API soporta este volumen de tráfico?

Eso es prueba de carga y rendimiento.

Pero hay otra pregunta igual de importante:

¿La API sigue devolviendo respuestas correctas después de este cambio?

Eso es prueba funcional y de regresión. Ahí encaja Apidog.

Apidog es una plataforma API para diseño, depuración, mocking, documentación y pruebas automatizadas. Sus escenarios de prueba agrupan endpoints en pasos lógicos con condiciones como if, for y foreach, lo que permite validar:

  • códigos de estado,
  • cuerpos de respuesta,
  • contratos,
  • flujos funcionales completos.

Puedes ejecutar esos escenarios en CI con la CLI de Apidog para bloquear merges cuando una regresión rompe la API.

El límite es importante: Apidog incluye una función de prueba de rendimiento, pero está limitada a un máximo de 100 usuarios virtuales. Es útil para detectar regresiones evidentes, pero no reemplaza a Artillery en escenarios de alta concurrencia.

Para cargas distribuidas y modeladas como código a gran escala, usa Artillery. Para pruebas funcionales, de contrato y regresión en CI, usa Apidog.

Este contexto también se cubre en el artículo sobre pruebas de carga de APIs sin Python, y la función de 100 VUs de Apidog se explica en pruebas de rendimiento de API en Apidog.

Ejecutar pruebas de Apidog en CI

La CLI de Apidog se instala desde npm. El comando apidog run usa solo banderas; no recibe archivos posicionales.

npm install -g apidog-cli

apidog run \
  --access-token $APIDOG_ACCESS_TOKEN \
  -t <TEST_SCENARIO_ID> \
  -e <ENVIRONMENT_ID> \
  -r cli,junit \
  --out-dir ./apidog-reports
Enter fullscreen mode Exit fullscreen mode

Qué hace cada bandera:

  • --access-token: token de acceso de Apidog.
  • -t: ID del escenario de prueba.
  • -e: ID del entorno.
  • -r cli,junit: genera salida en consola y reporte JUnit XML.
  • --out-dir: directorio donde se guardan los reportes.

Ejemplo de GitHub Actions:

name: API regression tests

on: [pull_request]

jobs:
  apidog:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "lts/*"

      - run: npm install -g apidog-cli

      - run: |
          apidog run \
            --access-token $APIDOG_ACCESS_TOKEN \
            -t $APIDOG_TEST_SCENARIO_ID \
            -e $APIDOG_ENVIRONMENT_ID \
            -r cli,junit \
            --out-dir ./apidog-reports
        env:
          APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
          APIDOG_TEST_SCENARIO_ID: ${{ secrets.APIDOG_TEST_SCENARIO_ID }}
          APIDOG_ENVIRONMENT_ID: ${{ secrets.APIDOG_ENVIRONMENT_ID }}

      - uses: actions/upload-artifact@v4
        with:
          name: apidog-reports
          path: ./apidog-reports
Enter fullscreen mode Exit fullscreen mode

Para un tutorial paso a paso, consulta el tutorial de la CLI de Apidog. Para patrones de diseño de pipelines, revisa estas mejores prácticas de CI/CD para pruebas de API.

Una estrategia práctica es:

  1. Ejecutar pruebas funcionales de Apidog en cada pull request.
  2. Ejecutar pruebas de carga de Artillery manualmente, por cron o antes de releases.
  3. Usar umbrales de latencia y errores para bloquear despliegues riesgosos.
  4. Guardar reportes JSON/JUnit como artefactos del pipeline.

Preguntas frecuentes

¿Qué es la prueba de carga con Artillery?

Es la práctica de usar Artillery para simular muchos usuarios virtuales accediendo a una API. Defines el perfil de carga y los flujos de solicitudes en YAML, ejecutas la prueba y mides latencia, tasa de solicitudes y errores para entender cómo se comporta el sistema bajo estrés.

¿Artillery es gratuito y open source?

Sí. La CLI principal de Artillery es gratuita y open source. Se distribuye en npm como el paquete artillery. También existe Artillery Cloud, una oferta alojada para visualizar resultados, pero puedes ejecutar pruebas de carga localmente y en CI sin usarla.

¿Cómo se ejecuta una prueba de carga con Artillery?

Instala Artillery:

npm install -g artillery@latest
Enter fullscreen mode Exit fullscreen mode

Crea un archivo YAML con config y scenarios, y ejecútalo:

artillery run script.yml
Enter fullscreen mode Exit fullscreen mode

Artillery imprimirá métricas en vivo y un resumen al final.

¿Cómo se genera un informe de Artillery?

En Artillery v2, genera un archivo JSON con:

artillery run --output report.json script.yml
Enter fullscreen mode Exit fullscreen mode

El antiguo comando artillery report para crear HTML fue eliminado. En su lugar, analiza el JSON con jq, usa Artillery Cloud con --record --key, o envía métricas a tu stack de observabilidad con publish-metrics u OpenTelemetry.

Artillery vs k6 o JMeter: ¿cuál deberías usar?

Los tres pueden manejar cargas a gran escala:

  • Artillery usa YAML declarativo y corre sobre Node.js.
  • k6 usa scripts JavaScript con un enfoque code-first.
  • JMeter usa una GUI, está basado en Java y tiene un ecosistema amplio de plugins.

Si tu equipo trabaja en el ecosistema JavaScript y prefiere configuración declarativa, Artillery es una buena opción. Si necesitas comparar más herramientas, la comparación Gatling vs JMeter cubre ventajas y desventajas con más profundidad.

La recomendación práctica: elige la herramienta cuyo modelo encaje mejor con tu equipo y combínala con pruebas funcionales en CI para cubrir rendimiento y correctitud.

Top comments (0)