Contents

Bruno: Guía práctica para pruebas de API

Facilitando la curva de entrada al API Testing con Bruno

Introducción

Bruno es una herramienta de código abierto para el testeo de APIs que destaca por su sencillez, rendimiento y enfoque git-friendly. A diferencia de otras soluciones, Bruno almacena las colecciones localmente como archivos de texto, facilitando enormemente la colaboración a través del control de versiones y la integración en pipelines CI.

Otra de las ventajas principales es que se puede trabajar de manera totalmente productiva desde su interfaz gráfica como manipulando directamente los ficheros de texto desde un IDE. Esta característica facilita la curva de aprendizaje de esta herramienta.

En este artículo, exploraremos las principales características de Bruno que lo hacen especialmente útil para los equipos de testing y desarrollo.

Instalación

Aplicación de escritorio

Bruno está disponible para Windows, macOS y Linux. Se puede descargar directamente desde:

https://www.usebruno.com/downloads

Una vez abierta, la aplicación de escritorio tiene esta pinta:

/images/substack/bruno-api/bruno-api-1.png

Es muy intuitiva lo que facilita crear o abrir colecciones. En este caso, si no quieres empezar de cero, puedes descargar este repo de ejemplo:

https://github.com/morvader/BrunoExample

CLI (Interfaz de línea de comandos)

Para automatizar pruebas y ejecutarlas por línea de comando en local o pipelines tendrás que instalar su aplicación node.

Usando npm:

npm install -g @usebruno/cli

Usando Homebrew (macOS):

brew install usebruno/tap/bruno

Verificar la instalación:

bru --version

También hay disponible un plugin de VsCode que os permitirá trabajar y ejecutar peticiones directamente desde el IDE.

/images/substack/bruno-api/bruno-api-2.png

Organización de colecciones

Uno de los puntos fuertes de Bruno es cómo organiza las colecciones. Los archivos .bru se almacenan en tu sistema de archivos, lo que permite una estructura jerárquica natural:

JsonPlaceholder/
├── bruno.json              # Collection configuration
├── environments/
│   ├── Development.bru
│   └── Production.bru
├── Users/
│   ├── get-users.bru
│   ├── get-user-by-id.bru
│   └── create-user.bru
└── Posts/
    ├── get-posts.bru
    └── create-post.bru

Ventajas de trabajar con ficheros de texto

Los archivos .bru son texto plano, lo que permite:

  • Un control de versiones natural: Cada cambio puede ser rastreado con Git
  • Revisión del código: Los cambios en las pruebas se revisan en pull requests
  • Colaboración sin fricciones: El equipo trabaja como con el código fuente
  • Branching: Desarrollo paralelo de pruebas en diferentes ramas

Variables y entornos

Definición de Entornos

Bruno permite gestionar múltiples entornos (Desarrollo, Staging, Producción). Los archivos de entorno se guardan en la carpeta environments/:

environments/Producción.bru:

vars {
  baseUrl: https://jsonplaceholder.typicode.com
  apiTimeout: 5000
}

environments/Development.bru:

vars {
  baseUrl: http://localhost:3000
  apiTimeout: 10000
}

Uso de variables

Las variables se referencian con llaves dobles en las peticiones:

get {
  url: {{baseUrl}}/users/userId
  body: none
  auth: none
}

headers {
  Authorization: Bearer {{apiKey}}
  Content-Type: application/json
}

Añadiendo Tests de API

Bruno ofrece dos formas de definir validaciones: aserciones declarativas y tests JavaScript.

Aserciones declarativas

La forma más sencilla de validar respuestas sin escribir código:

assert {
  res.status: eq 200
  res.body: isArray
  res.body.length: gt 0
  res.body[0].email: contains @
  res.responseTime: lt 2000
}

Operadores disponibles:

  • eq: igual a
  • neq: no igual a
  • gt: mayor que
  • gte: mayor o igual que
  • lt: menor que
  • lte: menor o igual que
  • contains: contiene
  • notContains: no contiene
  • isArray: es una matriz
  • isObject: es un objeto
  • isString: es una cadena
  • isNumber: es un número
  • isBoolean: es un boolean
  • isNull: es nulo

Código JavaScript

Para validaciones más complejas, Bruno admite pruebas con Chai:

tests {
  test("should return valid users", function () {
    expect(res.getStatus()).to.equal(200);
    expect(res.getBody()).to.be.an('array');
    expect(res.getBody().length).to.be.greaterThan(0);
  });

  test("each user should have required fields", function () {
    const users = res.getBody();
    users.forEach(user => {
      expect(user).to.have.property('id');
      expect(user).to.have.property('name');
      expect(user).to.have.property('email');
      expect(user.email).to.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
    });
  });

  test("response time should be acceptable", function () {
    expect(res.getResponseTime()).to.be.lessThan(2000);
  });
}

Ejemplo de solicitud completa con pruebas

meta {
  name: Create User
  type: http
  seq: 2
}

post {
  url: baseUrl/users
  body: json
  auth: none
}

body:json {
  {
    "name": "Test User",
    "username": "testuser",
    "email": "test@example.com"
  }
}

assert {
  res.status: eq 201
  [res.body.name]: eq Test User
}

tests {
  test("should create user successfully", function () {
    expect(res.getStatus()).to.equal(201);
    const body = res.getBody();
    expect(body).to.have.property('id');
    expect(body.name).to.equal('Test User');
  });

  test("should save user ID for next requests", function () {
    const userId = res.getBody().id;
    bru.setVar("createdUserId", userId);
    expect(userId).to.be.a('number');
  });
}

Ejecución en consola

Una de las características más potentes de Bruno es su CLI, fundamental para la automatización y CI/CD.

Ejecutar una petición individual

bru run get-users.bru --env Production

Ejecutar toda la colección

Desde el directorio raíz de la colección:

bru run . --env Production

Ejemplo de salida:

Running Collection: JsonPlaceholder

✓ get-users (234ms)
  ✓ should return valid users
  ✓ each user should have required fields
  ✓ response time should be acceptable

✓ create-user (189ms)
  ✓ should create user successfully
  ✓ should save user ID for next requests

✓ get-user-by-id (156ms)
  ✓ should return correct user

Tests: 6 passed, 6 total
Time: 1.579s

Opciones útiles

# Run requests with a specific tag
bru run . --env Production --tags smoke

# Run requests with multiple tags
bru run . --env Production --tags "smoke,critical"

# Run all requests from a specific folder
bru run Users/ --env Production

# Run a specific request within a folder
bru run Users/get-users.bru --env Production

# Combine specific folder with tags
bru run Posts/ --env Production --tags regression

# Verbose mode for debugging
bru run . --env Production --verbose

Generación de informes

Informe HTML:

bru run . --env Production --reporter-html results.html

Informe JSON:

bru run . --env Production --reporter-json results.json

Informe JUnit XML (para CI/CD):

bru run . --env Production --reporter-junit results.xml

Integración CI/CD

GitLab CI

api-tests:
  stage: test
  image: node:18
  script:
    - npm install -g @usebruno/cli
    - cd JsonPlaceholder
    - bru run . --env Production --reporter-junit results.xml
  artifacts:
    when: always
    reports:
      junit: results.xml

Ejemplo práctico

Basado en el repositorio BrunoExample:

1. Clonar y explorar

git clone https://github.com/morvader/BrunoExample.git
cd BrunoExample

2. Abrir con Bruno Desktop

  1. Abrir Bruno
  2. Haga clic en “Abrir colección”
  3. Selecciona la carpeta JsonPlaceholder

3. Ejecutar desde CLI

cd JsonPlaceholder
bru run . --env Production --reporter-html results.html

4. Ver resultados

Abra results.html en su navegador para ver el informe detallado.

Conclusiones

Bruno ofrece un enfoque moderno a las pruebas de API con claras ventajas:

  • Git-friendly: Integración natural con el control de versiones
  • Organización flexible: Estructura de carpetas intuitiva
  • Potentes variables: Gestión sencilla de múltiples entornos
  • Pruebas versátiles: Aserciones declarativas o JavaScript según sea necesario
  • CLI robusta: Automatización sencilla en conductos CI/CD
  • Ligero y rápido: Sin dependencias de servicios en la nube
  • De código abierto: Control total sobre la herramienta y los datos

Ideal para equipos que buscan simplicidad, control y facilidad de integración en sus flujos de trabajo de desarrollo.

Recursos