Un test de UI que hace clic en "Realizar Pedido" y ve una pantalla de confirmación no te dice si el pedido realmente se escribió en la base de datos. SQL sí lo hace. Este artículo cubre los cinco patrones de consultas que manejan el 80% del trabajo de base de datos en QA: SELECT con WHERE, JOINs, COUNT y GROUP BY, verificaciones de NULL, y cómo ejecutar consultas directamente desde tests de Playwright para verificar la persistencia de datos.

Por qué los QA engineers necesitan SQL

Los tests de UI verifican lo que el usuario ve. SQL verifica lo que realmente ocurrió.

Cuando un test hace clic en "Realizar Pedido" y ve una pantalla de confirmación, sabes que la UI respondió. No sabes si el pedido se guardó. No sabes si se asignó el estado correcto. No sabes si la clave foránea se escribió correctamente. La única manera de verificar eso es mirar la base de datos directamente.

Casos de uso de SQL en QA:

  • Verificar que los datos se guardaron después de una acción de UI (envío de formulario, carga de archivo, pago)
  • Configurar datos de prueba directamente en lugar de hacer 10 clics en la UI
  • Verificar datos que la UI no expone (logs de auditoría, flags internos, registros borrados de forma lógica)
  • Reproducir bugs verificando el estado de la base de datos cuando algo falló
  • Validar migraciones después de un deploy que cambió el esquema

Cuando una oferta de trabajo dice "se requiere experiencia en SQL", esto es lo que quieren decir. No procedimientos almacenados, no optimización de consultas, no administración de bases de datos. Sentencias SELECT con condiciones.

La herramienta: cualquier cliente SQL

No necesitas conocer un producto de base de datos específico. La sintaxis de consultas es casi idéntica en PostgreSQL, MySQL y SQLite. Para practicar:

  • TablePlus (Mac/Windows): interfaz limpia, el tier gratuito es suficiente
  • DBeaver: gratuito, funciona con todos los tipos de bases de datos
  • psql: línea de comandos de PostgreSQL, siempre disponible
  • Cualquier test de Playwright con un paquete pg o mysql2 también puede ejecutar consultas directamente

Para los ejemplos a continuación, la estructura está basada en el esquema de base de datos de lab.becomeqa.com.

Patrón 1: SELECT

Lo más común que vas a hacer:

-- Obtener todos los usuarios
SELECT * FROM users;

-- Obtener columnas específicas
SELECT id, email, created_at FROM users;

-- Obtener un usuario por email
SELECT * FROM users WHERE email = 'admin@becomeqa.com';

-- Obtener usuarios creados en los últimos 7 días
SELECT * FROM users WHERE created_at > NOW() - INTERVAL '7 days';

SELECT * obtiene todas las columnas. SELECT id, email obtiene solo esas columnas. WHERE filtra filas. Eso es el 90% de lo que necesitas.

En contexto de QA

-- Después de un test de registro, verificar que el usuario fue creado
SELECT id, email, role, is_active 
FROM users 
WHERE email = 'testuser_1234567@test.com';

Si esto devuelve una fila, el usuario se guardó. Si no devuelve nada, el registro falló silenciosamente aunque la UI mostrara éxito.

Patrón 2: WHERE con condiciones

Combinar condiciones:

-- AND: ambas condiciones deben ser verdaderas
SELECT * FROM items 
WHERE status = 'completed' AND user_id = 42;

-- OR: cualquiera de las condiciones debe ser verdadera
SELECT * FROM items 
WHERE status = 'pending' OR status = 'in_progress';

-- IN: coincidir con cualquier valor de una lista
SELECT * FROM items 
WHERE status IN ('pending', 'in_progress', 'completed');

-- NOT: excluir filas
SELECT * FROM items WHERE status != 'deleted';

-- LIKE: coincidencia parcial de string (% es comodín)
SELECT * FROM users WHERE email LIKE '%@test.com';

-- IS NULL: verificar valores faltantes
SELECT * FROM items WHERE deleted_at IS NULL;
SELECT * FROM items WHERE deleted_at IS NOT NULL;

En contexto de QA

-- Verificar que el borrado lógico funcionó (deleted_at debería estar asignado)
SELECT id, title, deleted_at 
FROM items 
WHERE id = 99;

-- Encontrar todos los datos de prueba para limpiar después de una ejecución
SELECT * FROM users WHERE email LIKE '%testuser_%@test.com';

Patrón 3: JOIN

Los datos reales viven en múltiples tablas. Un ítem de viaje pertenece a un usuario. Un pedido pertenece a un cliente y contiene productos. Necesitas JOIN para ver el panorama completo.

-- JOIN básico: ítems con el email de su propietario
SELECT items.id, items.title, items.status, users.email
FROM items
JOIN users ON items.user_id = users.id;

-- Filtrar el resultado del join
SELECT items.id, items.title, users.email
FROM items
JOIN users ON items.user_id = users.id
WHERE users.email = 'admin@becomeqa.com';

El patrón siempre es:

SELECT [columnas que quieres]
FROM [tabla principal]
JOIN [tabla relacionada] ON [cómo se conectan]
WHERE [filtro opcional]

En contexto de QA

-- Después de añadir un ítem como admin, verificar que está vinculado al usuario correcto
SELECT items.title, items.status, users.email AS owner
FROM items
JOIN users ON items.user_id = users.id
WHERE items.title = 'Tokyo'
ORDER BY items.created_at DESC
LIMIT 1;

Patrón 4: COUNT y funciones de agregación

Cuando necesitas números, no filas:

-- ¿Cuántos usuarios hay?
SELECT COUNT(*) FROM users;

-- ¿Cuántos usuarios activos?
SELECT COUNT(*) FROM users WHERE is_active = true;

-- ¿Cuántos ítems por estado?
SELECT status, COUNT(*) AS total
FROM items
GROUP BY status;

-- Fecha de creación del ítem más reciente
SELECT MAX(created_at) FROM items;

-- Total de ítems por usuario
SELECT user_id, COUNT(*) AS item_count
FROM items
GROUP BY user_id
ORDER BY item_count DESC;

En contexto de QA

-- Después de un test de importación masiva, verificar que se creó la cantidad correcta de registros
SELECT COUNT(*) FROM items WHERE created_at > '2026-05-15 10:00:00';

-- Verificar que los datos de prueba están aislados (sin contaminación entre ejecuciones)
SELECT user_id, COUNT(*) FROM items GROUP BY user_id;

Patrón 5: ORDER BY y LIMIT

Controlar qué filas obtienes y en qué orden:

-- Ítems creados más recientemente primero
SELECT * FROM items ORDER BY created_at DESC;

-- Los más antiguos primero
SELECT * FROM items ORDER BY created_at ASC;

-- Solo los 5 más recientes
SELECT * FROM items ORDER BY created_at DESC LIMIT 5;

-- Página 2 de resultados (filas 11 a 20)
SELECT * FROM items ORDER BY id LIMIT 10 OFFSET 10;

En contexto de QA

-- Después de que un test crea un ítem, obtener el que se acaba de crear
SELECT * FROM items 
WHERE user_id = 42 
ORDER BY created_at DESC 
LIMIT 1;

Juntando todo: una consulta de verificación completa

Flujo de un test: el usuario inicia sesión, añade un ítem de viaje llamado "París", lo marca como "Completado". Así verificas la operación completa en SQL:

SELECT 
    items.id,
    items.title,
    items.status,
    items.created_at,
    users.email AS owner
FROM items
JOIN users ON items.user_id = users.id
WHERE items.title = 'París'
    AND items.status = 'completed'
    AND users.email = 'admin@becomeqa.com'
ORDER BY items.created_at DESC
LIMIT 1;

Si esto devuelve una fila, el flujo completo funcionó de principio a fin. Si no devuelve nada, algo falló silenciosamente entre el login y la actualización de estado.

Usar SQL en tests de Playwright

Puedes ejecutar SQL directamente desde tu código de tests usando una librería cliente de base de datos:

import { test, expect } from '@playwright/test';
import { Client } from 'pg'; // npm install pg

test('el ítem se guarda en la base de datos después de crearlo', async ({ page }) => {
    // Realizar la acción de UI
    await page.goto('/');
    // ... login, añadir ítem llamado 'Tokyo' ...

    // Verificar en la base de datos
    const db = new Client({ connectionString: process.env.DATABASE_URL });
    await db.connect();
    
    const result = await db.query(
        'SELECT * FROM items WHERE title = $1 ORDER BY created_at DESC LIMIT 1',
        ['Tokyo']
    );
    
    expect(result.rows.length).toBe(1);
    expect(result.rows[0].status).toBe('planned');
    
    await db.end();
});

Este patrón es poderoso: acción de UI + verificación de base de datos en un test. El test de UI prueba que la app respondió correctamente; la consulta de base de datos prueba que los datos realmente se persistieron.

Errores comunes

Usar SELECT * en tests de producción

Está bien para depurar, pero nombra las columnas explícitamente en tests automatizados. Cuando se añade o elimina una columna, SELECT * oculta el cambio.

Olvidar WHERE en un DELETE

Si estás limpiando datos de prueba con DELETE FROM items WHERE email LIKE '%test%', siempre verifica el WHERE antes de ejecutar. DELETE FROM items sin un WHERE borra todo.

No usar consultas parametrizadas en el código

Nunca construyas strings de SQL concatenando input del usuario. Usa placeholders $1 como se muestra arriba para prevenir SQL injection.

Leer datos desactualizados

Algunas bases de datos tienen aislamiento de transacciones que significa que necesitas COMMIT de una transacción antes de que otra conexión pueda ver los cambios. Si tu test escribe datos y luego los consulta desde una conexión diferente, verifica que la transacción fue commiteada.

Lo que no necesitás (todavía)

  • Subconsultas
  • Funciones de ventana (ROW_NUMBER, RANK)
  • CTEs (cláusulas WITH)
  • Procedimientos y funciones almacenadas
  • Índices de base de datos y planificación de consultas
  • Diseño de esquemas y normalización

Esto importa para los desarrolladores de bases de datos. Para QA, lees datos. Los cinco patrones anteriores son todo el trabajo el 95% del tiempo.

Preguntas frecuentes

¿En qué base de datos debería aprender SQL?

PostgreSQL. Es la más común en las aplicaciones web modernas, tiene las mejores herramientas, y la sintaxis es lo suficientemente estándar como para que cambiar a MySQL o SQLite tome minutos. Instala TablePlus, conéctate a cualquier instancia de PostgreSQL y practica ahí.

¿Puedo practicar SQL sin una aplicación real?

Sí. Sitios como sqlfiddle.com y db-fiddle.com te permiten crear tablas y ejecutar consultas en el navegador sin instalar nada. Crea una tabla users y una tabla items, inserta algunas filas y practica los cinco patrones anteriores.

¿Debería escribir tests SQL o solo usarlos para depurar?

Ambos. SQL es invaluable para depuración manual. Cuando no puedes entender por qué falla un test, verifica la base de datos. También es valioso en tests automatizados para verificación de datos que la UI no puede proporcionar. Empieza con la depuración, añade aserciones de base de datos automatizadas una vez que te sientes cómodo con las consultas.

¿Cuál es la diferencia entre las bases de datos SQL?

Para propósitos de QA, casi ninguna. PostgreSQL usa $1 para parámetros, MySQL usa ?, pero la sintaxis de SELECT/WHERE/JOIN es idéntica. Los cinco patrones anteriores funcionan en los tres.

→ See also: Cómo Funciona Internet para Testers | API Testing con Playwright: Más Allá de la UI