Matrix testing es una de las técnicas más poderosas para asegurar que tu aplicación funcione en múltiples entornos, configuraciones y plataformas. En pipelines CI/CD modernos, matrix testing te permite ejecutar la misma suite de pruebas en diferentes combinaciones de variables automáticamente. Este tutorial completo te guiará a través de la implementación de estrategias de matrix testing que escalan con tu flujo de desarrollo.
¿Qué es Matrix Testing?
Matrix testing, también conocido como pruebas combinatorias, es una técnica donde ejecutas pruebas en múltiples dimensiones de variables de configuración simultáneamente. En lugar de probar cada configuración por separado, creas una matriz de todas las combinaciones posibles y ejecutas pruebas para cada permutación.
Por ejemplo, si necesitas probar tu aplicación en:
- 3 sistemas operativos (Linux, macOS, Windows)
- 3 versiones del lenguaje de programación (Node.js 16, 18, 20)
- 2 versiones de base de datos (PostgreSQL 13, 14)
Las pruebas tradicionales requerirían 18 configuraciones manuales separadas. Matrix testing automatiza todo este proceso, ejecutando todas las combinaciones en paralelo.
Requisitos Previos
Antes de implementar matrix testing, asegúrate de tener:
Herramientas Requeridas:
- Plataforma CI/CD (GitHub Actions, GitLab CI, Jenkins o CircleCI)
- Sistema de control de versiones (Git)
- Docker (opcional pero recomendado para entornos reproducibles)
- Conocimiento básico de YAML para configuración CI
Conocimientos Técnicos:
- Comprensión de conceptos de pipeline CI/CD
- Familiaridad con tu plataforma CI elegida
- Habilidades básicas de scripting (Bash, Python o JavaScript)
Configuración del Entorno:
- Acceso a tu repositorio con CI/CD habilitado
- Permisos apropiados para modificar configuraciones de pipeline
- Suite de pruebas ya implementada
Paso 1: Define las Dimensiones de tu Matriz de Pruebas
Comienza identificando qué variables necesitan ser probadas en múltiples valores. Las dimensiones comunes incluyen:
Variables de Infraestructura:
- Sistemas operativos (ubuntu-latest, macos-latest, windows-latest)
- Arquitectura (x86, ARM64)
- Proveedores de nube (AWS, Azure, GCP)
Variables de Aplicación:
- Versiones del lenguaje de programación
- Versiones de frameworks
- Versiones de dependencias
- Sistemas de bases de datos y versiones
Variables de Configuración:
- Tipos de entorno (desarrollo, staging, producción)
- Feature flags
- Endpoints de integración
Crea un documento listando tus dimensiones críticas:
# matrix-config.yaml
dimensions:
os: [ubuntu-22.04, ubuntu-20.04, macos-13, windows-2022]
node_version: [16, 18, 20]
database: [postgres:13, postgres:14, postgres:15]
Punto de Verificación: Revisa tus dimensiones con tu equipo. Prioriza combinaciones que representen entornos reales de usuarios. Evita probar combinaciones que no existen en producción.
Paso 2: Implementa Matrix Testing en GitHub Actions
GitHub Actions proporciona soporte nativo para estrategia de matriz. Aquí está cómo implementarlo:
# .github/workflows/matrix-tests.yml
name: Matrix Testing
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
name: Test on ${{ matrix.os }} with Node ${{ matrix.node }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [16, 18, 20]
include:
# Añade combinaciones específicas con configuración extra
- os: ubuntu-latest
node: 20
experimental: true
exclude:
# Omite combinaciones problemáticas
- os: macos-latest
node: 16
fail-fast: false # Continúa probando otras combinaciones aunque una falle
max-parallel: 5 # Limita trabajos concurrentes
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
flags: ${{ matrix.os }}-node-${{ matrix.node }}
Salida Esperada: Esta configuración crea 8 trabajos (3 OS × 3 versiones de Node - 1 combinación excluida). Cada trabajo se ejecuta independientemente, y verás resultados para cada combinación en la UI de GitHub Actions.
Paso 3: Implementa Matriz Avanzada con Servicios de Base de Datos
Las aplicaciones del mundo real frecuentemente requieren pruebas con diferentes bases de datos. Aquí está cómo añadir contenedores de servicios a tu matriz:
name: Matrix with Database Testing
jobs:
integration-test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [18, 20]
database:
- type: postgres
version: '13'
port: 5432
- type: postgres
version: '14'
port: 5432
- type: mysql
version: '8.0'
port: 3306
services:
database:
image: ${{ matrix.database.type }}:${{ matrix.database.version }}
env:
POSTGRES_PASSWORD: testpass
MYSQL_ROOT_PASSWORD: testpass
ports:
- ${{ matrix.database.port }}:${{ matrix.database.port }}
options: >-
--health-cmd="pg_isready"
--health-interval=10s
--health-timeout=5s
--health-retries=5
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Configure database connection
run: |
echo "DATABASE_TYPE=${{ matrix.database.type }}" >> $GITHUB_ENV
echo "DATABASE_PORT=${{ matrix.database.port }}" >> $GITHUB_ENV
- name: Run integration tests
run: npm run test:integration
env:
DATABASE_URL: ${{ matrix.database.type }}://user:testpass@localhost:${{ matrix.database.port }}/testdb
Punto de Verificación: Ejecuta este workflow y verifica que cada servicio de base de datos inicie correctamente. Revisa los logs para asegurar que las conexiones de base de datos se establezcan antes de que las pruebas se ejecuten.
Paso 4: Optimiza la Ejecución de Matriz con Matrices Dinámicas
Para matrices grandes, puedes generar combinaciones dinámicamente para reducir redundancia:
jobs:
prepare-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- name: Generate dynamic matrix
id: set-matrix
run: |
# Genera matriz basada en archivos cambiados o condiciones
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Matriz limitada para PRs
echo 'matrix={"os":["ubuntu-latest"],"node":[20]}' >> $GITHUB_OUTPUT
else
# Matriz completa para rama main
echo 'matrix={"os":["ubuntu-latest","macos-latest","windows-latest"],"node":[16,18,20]}' >> $GITHUB_OUTPUT
fi
test:
needs: prepare-matrix
runs-on: ${{ matrix.os }}
strategy:
matrix: ${{ fromJson(needs.prepare-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- name: Run tests
run: echo "Testing on ${{ matrix.os }} with Node ${{ matrix.node }}"
Salida Esperada: Los pull requests ejecutarán solo 1 trabajo, mientras que los pushes a main ejecutarán la matriz completa de 9 trabajos. Esto reduce significativamente los costos y el tiempo de CI para desarrollo rutinario.
Paso 5: Implementa Matrix Testing en GitLab CI
GitLab CI usa trabajos paralelos para matrix testing:
# .gitlab-ci.yml
.test_template:
stage: test
script:
- npm ci
- npm test
test:
extends: .test_template
image: node:${NODE_VERSION}
parallel:
matrix:
- NODE_VERSION: ['16', '18', '20']
OS: ['ubuntu', 'alpine']
DATABASE:
- TYPE: 'postgres'
VERSION: '13'
- TYPE: 'postgres'
VERSION: '14'
services:
- name: ${DATABASE_TYPE}:${DATABASE_VERSION}
alias: database
variables:
DATABASE_URL: "${DATABASE_TYPE}://user:pass@database:5432/testdb"
before_script:
- echo "Testing Node ${NODE_VERSION} on ${OS} with ${DATABASE_TYPE} ${DATABASE_VERSION}"
Punto de Verificación: GitLab creará 12 trabajos (3 versiones de Node × 2 OS × 2 versiones de base de datos). Revisa el gráfico del pipeline para visualizar todas las combinaciones.
Paso 6: Añade Matrix Testing para Jenkins
Jenkins requiere un enfoque más programático usando Groovy:
// Jenkinsfile
pipeline {
agent none
stages {
stage('Matrix Build') {
matrix {
axes {
axis {
name 'OS'
values 'linux', 'windows', 'mac'
}
axis {
name 'NODE_VERSION'
values '16', '18', '20'
}
axis {
name 'DATABASE'
values 'postgres:13', 'postgres:14', 'mysql:8.0'
}
}
excludes {
exclude {
axis {
name 'OS'
values 'mac'
}
axis {
name 'NODE_VERSION'
values '16'
}
}
}
stages {
stage('Test') {
agent {
docker {
image "node:${NODE_VERSION}"
label "${OS}"
}
}
steps {
sh 'npm ci'
sh 'npm test'
}
}
}
}
}
}
post {
always {
publishHTML([
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: "Coverage Report - ${OS}-${NODE_VERSION}-${DATABASE}"
])
}
}
}
Salida Esperada: Jenkins crea una matriz visual con todas las combinaciones, permitiéndote profundizar en resultados de prueba específicos para cada configuración.
Paso 7: Implementa Smart Matrix Testing con Caching
Optimiza el tiempo de ejecución de matriz usando estrategias efectivas de caché:
name: Optimized Matrix Testing
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
node: [18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- name: Cache node modules
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Cache build artifacts
uses: actions/cache@v3
with:
path: dist
key: ${{ runner.os }}-build-${{ matrix.node }}-${{ github.sha }}
- name: Run tests
run: npm test
Punto de Verificación: Monitorea tu tiempo de ejecución del workflow. El caché configurado correctamente debería reducir el tiempo de ejecución en 30-50% en ejecuciones subsiguientes.
Mejores Prácticas para Matrix Testing
1. Prioriza Combinaciones Críticas
No todas las combinaciones son igualmente importantes. Usa priorización basada en datos:
strategy:
matrix:
include:
# Configuraciones críticas de producción (mayor prioridad)
- os: ubuntu-latest
node: 20
priority: critical
# Configuraciones comunes de usuarios
- os: ubuntu-latest
node: 18
priority: high
# Casos extremos y compatibilidad futura
- os: macos-latest
node: 20
priority: medium
2. Usa Fail-Fast Estratégicamente
Controla cómo las fallas de matriz afectan tu pipeline:
strategy:
fail-fast: false # Prueba todas las combinaciones aunque algunas fallen
matrix:
# ... configuración de matriz
Establece fail-fast: true cuando:
- Ejecutes con recursos CI limitados
- Pruebes características críticas donde una falla indica problemas sistémicos
- Depures combinaciones específicas
Establece fail-fast: false cuando:
- Investigues problemas específicos de plataforma
- Generes reportes de compatibilidad completos
- Algunas combinaciones sean conocidas por ser inestables
3. Implementa Recolección de Artefactos de Matriz
Recolecta y organiza resultados de prueba de todas las combinaciones de matriz:
steps:
- name: Run tests
run: npm test -- --coverage
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.os }}-node-${{ matrix.node }}
path: |
coverage/
test-results/
retention-days: 30
- name: Generate matrix report
if: always()
run: |
echo "## Test Results: ${{ matrix.os }} - Node ${{ matrix.node }}" >> $GITHUB_STEP_SUMMARY
echo "Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
echo "$(cat test-results/summary.txt)" >> $GITHUB_STEP_SUMMARY
4. Monitorea el Rendimiento de Matriz
Rastrea métricas de ejecución de matriz para optimizar costos y tiempo:
- name: Report matrix metrics
run: |
echo "Matrix combination: ${{ matrix.os }}-${{ matrix.node }}"
echo "Start time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
npm test
echo "End time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "Status: ${{ job.status }}"
Usa estas métricas para identificar:
- Las combinaciones más lentas que necesitan optimización
- Configuraciones que fallan frecuentemente
- Dimensiones de matriz redundantes o innecesarias
Errores Comunes y Soluciones
Error 1: Explosión de Matriz
Problema: Demasiadas dimensiones crean cientos de combinaciones, sobrecargando recursos CI.
Solución: Usa exclusiones estratégicas y matrices condicionales:
strategy:
matrix:
os: [ubuntu, macos, windows]
node: [16, 18, 20]
database: [postgres, mysql, mongodb]
# ¡Esto crea 27 combinaciones!
exclude:
# Elimina combinaciones de producción poco probables
- os: windows
database: mongodb
- os: macos
node: 16
# Ahora reducido a 23 combinaciones
Error 2: Contención de Recursos
Problema: Todos los trabajos de matriz comienzan simultáneamente, causando agotamiento de recursos o alcanzando límites de tasa.
Solución: Implementa paralelismo controlado:
strategy:
max-parallel: 4 # Limita trabajos concurrentes
matrix:
# ... configuración
Error 3: Entornos de Prueba Inconsistentes
Problema: Las pruebas pasan en algunas combinaciones de matriz pero fallan en otras debido a diferencias de entorno.
Solución: Usa Docker para entornos consistentes:
jobs:
test:
runs-on: ${{ matrix.os }}
container:
image: node:${{ matrix.node }}
options: --user root
strategy:
matrix:
os: [ubuntu-latest]
node: [16, 18, 20]
Herramientas y Recursos
Herramientas Recomendadas
| Herramienta | Caso de Uso | Ventajas | Desventajas |
|---|---|---|---|
| GitHub Actions | Propósito general matrix testing | Soporte nativo de matriz, buena UI, gratis para repos públicos | Limitado a GitHub |
| GitLab CI | Entornos empresariales | Opción self-hosted, integrado con GitLab | Curva de aprendizaje para sintaxis de matriz |
| Jenkins | Sistemas legacy | Altamente personalizable, ecosistema de plugins | Configuración compleja, sintaxis verbosa |
| CircleCI | Workflows pesados en Docker | Excelente soporte Docker, paralelismo | El costo puede ser alto para matrices grandes |
Recursos Esenciales
- GitHub Actions Matrix Strategy Documentation
- GitLab CI Parallel Matrix Jobs
- Jenkins Matrix Project Plugin
Conclusión
Matrix testing transforma tu pipeline CI/CD de probar configuraciones individuales a validación integral multiplataforma. Al implementar las estrategias en este tutorial, puedes:
- Probar todas las combinaciones de plataforma críticas automáticamente
- Detectar bugs específicos de entorno temprano
- Reducir sobrecarga de pruebas manuales en 70-80%
- Construir confianza en compatibilidad multiplataforma
Conclusiones Clave:
- Comienza con una matriz mínima y expande basándote en fallas reales
- Usa matrices dinámicas para optimizar costos y tiempo de ejecución
- Prioriza combinaciones críticas sobre cobertura exhaustiva
- Monitorea y mejora continuamente el rendimiento de matriz
Próximos Pasos:
- Implementa una matriz básica para tu suite de pruebas más crítica
- Monitorea ejecución de matriz durante 2-3 semanas y recolecta métricas
- Expande dimensiones de matriz basándote en problemas de producción
- Considera implementar ejecución de pruebas paralelas para resultados aún más rápidos
Matrix testing no es solo sobre ejecutar más pruebas—es sobre ejecutar las pruebas correctas en el momento correcto en las configuraciones que más importan a tus usuarios.