El Peligro de los Falsos Positivos con H2 en Memoria
H2 tiene dialectos, funciones de bloqueo, tipos de datos JSON y comportamientos transaccionales diferentes a PostgreSQL o MySQL. Un test que pasa verde en H2 puede fallar en producción.
En una línea Levantar un contenedor real de PostgreSQL 16 con Testcontainers.
-- Upsert: en H2 la sintaxis y el comportamiento difieren
INSERT INTO etiqueta (nombre, usos) VALUES ('java', 1)
ON CONFLICT (nombre) DO UPDATE SET usos = etiqueta.usos + 1;
-- JSONB con operadores e índice GIN
SELECT id FROM tarea WHERE metadatos @> '{"origen": "jira"}';
-- Bloqueo pesimista saltando filas bloqueadas (colas de trabajo)
SELECT id FROM trabajo WHERE estado = 'PENDIENTE'
ORDER BY creado_en LIMIT 10
FOR UPDATE SKIP LOCKED;
-- Búsqueda sin distinguir mayúsculas
SELECT * FROM tarea WHERE titulo ILIKE '%spring%';
Cómo funciona por dentro
H2 en memoria es rápido y no necesita instalación, pero no es PostgreSQL. Incluso en modo de compatibilidad difiere en tipos (JSONB, arrays, UUID, rangos), funciones (ON CONFLICT, ILIKE, funciones de ventana avanzadas, generate_series), en cómo trata mayúsculas, en el bloqueo y en los niveles de aislamiento.
El resultado son falsos positivos: tests en verde con consultas que fallan en producción, y falsos negativos: código válido para PostgreSQL que no puedes probar porque H2 no lo entiende. Además, tus migraciones Flyway escritas para PostgreSQL a menudo no se ejecutan en H2, así que acabas manteniendo dos esquemas.
Testcontainers arranca la imagen oficial de PostgreSQL (la misma versión que producción) en Docker en pocos segundos. La confianza que da un test contra el motor real compensa con creces el coste de arranque.
Se conecta con Testing de IntegraciónDockerPostgreSQL