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:

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/cliUsando Homebrew (macOS):
brew install usebruno/tap/brunoVerificar la instalación:
bru --versionTambién hay disponible un plugin de VsCode que os permitirá trabajar y ejecutar peticiones directamente desde el IDE.

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.bruVentajas 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 aneq: no igual agt: mayor quegte: mayor o igual quelt: menor quelte: menor o igual quecontains: contienenotContains: no contieneisArray: es una matrizisObject: es un objetoisString: es una cadenaisNumber: es un númeroisBoolean: es un booleanisNull: 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 ProductionEjecutar toda la colección
Desde el directorio raíz de la colección:
bru run . --env ProductionEjemplo 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.579sOpciones ú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 --verboseGeneración de informes
Informe HTML:
bru run . --env Production --reporter-html results.htmlInforme JSON:
bru run . --env Production --reporter-json results.jsonInforme JUnit XML (para CI/CD):
bru run . --env Production --reporter-junit results.xmlIntegració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.xmlEjemplo práctico
Basado en el repositorio BrunoExample:
1. Clonar y explorar
git clone https://github.com/morvader/BrunoExample.git
cd BrunoExample2. Abrir con Bruno Desktop
- Abrir Bruno
- Haga clic en “Abrir colección”
- Selecciona la carpeta JsonPlaceholder
3. Ejecutar desde CLI
cd JsonPlaceholder
bru run . --env Production --reporter-html results.html4. 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
- Sitio oficial: https://www.usebruno.com/
- Documentación: https://docs.usebruno.com/
- Repositorio de ejemplo: https://github.com/morvader/BrunoExample