0

Testing #2: Datos Dinámicos con Verify «Scrubbing»

Cuando hacemos Snapshot Testing, el mayor enemigo es el determinismo. Si tu objeto tiene fechas, IDs autogenerados o tokens de sesión, el test fallará siempre porque esos valores cambian en cada ejecución. El Scrubbing es el proceso de interceptar esos valores y reemplazarlos por placeholders estáticos antes de guardar la «foto».

El Concepto: Antes y Después del Scrubbing

Imagina este objeto que representa una transacción de nuestra API:

Snapshot Recibido (Sin Scrubbing) – TEST FALLA CADA SEGUNDO

{
  "OrderId": "7b8e1a-45...", 
  "ProcessedAt": "2026-02-14T12:00:01.456Z",
  "ServerName": "NODE-PROD-01"
}

Snapshot Verificado (Con Scrubbing) – TEST ESTABLE

{
  "OrderId": "Guid_1",
  "ProcessedAt": "2026-02-14",
  "ServerName": "{Scrubbed}"
}

Tipos de Scrubbing (Tutorial Paso a Paso)

Verify ofrece tres niveles de limpieza dependiendo de qué tan profundo necesites llegar en el árbol de objetos.

A. Scrubbing Global (Recomendado para Guids y Fechas)

En lugar de hacerlo test por test, configuras Verify una vez para que siempre limpie ciertos patrones.

[ModuleInitializer]
public static void Initialize()
{
    // Reemplaza todos los GUIDs aleatorios por Guid_1, Guid_2, etc.
    VerifierSettings.ScrubGuids();
    
    // Normaliza las fechas para que no fallen por milisegundos
    VerifierSettings.ScrubDateTimes("yyyy-MM-dd");
}

B. Scrubbing de Miembros Específicos

Si quieres ocultar un campo sensible o uno que cambia por configuración de entorno:

[Fact]
public Task GetOrder_Scrubbed()
{
    var result = service.GetOrder();

    return Verify(result)
        .ScrubMember<Order>(o => o.ServerName)
        .ScrubMember("InternalTraceId"); // Por nombre de propiedad (string)
}

C. Scrubbing por Expresión Regular (RegEx)

Ideal para logs o strings complejos donde solo una parte es dinámica.

return Verify(logOutput)
    .ScrubLinesWithReplace(line => 
        Regex.Replace(line, @"Version=\d+\.\d+\.\d+", "Version=1.0.0"));

¿Cómo funciona el algoritmo de reemplazo?

Verify no solo borra el dato; lo mapea. Si en tu JSON aparece el mismo GUID tres veces, el motor de Scrubbing lo detectará y pondrá Guid_1 en todas esas apariciones para mantener la integridad referencial dentro del snapshot.

Estrategia de Contrapunto: Scrubbing vs. Datos Mockeados

EstrategiaVentajaDesventaja
Mocking FijoEl dato real nunca cambia (ej. usar fixedDateTime).Requiere inyectar abstracciones de tiempo en todo el código.
ScrubbingNo tocas el código de producción. El código sigue usando DateTime.Now.El snapshot pierde el «valor real» del dato (solo ves un placeholder).

Notas

  1. Prioriza ScrubGuids(): Es la causa #1 de fallos en Snapshot Testing. Actívalo globalmente en tu ensamblado de tests.
  2. Usa ScrubLines para Logs: Si estás testeando la salida de consola o logs de Serilog, limpia los timestamps de cada línea para evitar ruido.
  3. Cuidado con el Orden: Verify aplica los scrubbers en el orden en que los llamas. Primero limpia los tipos complejos y luego los strings generales.
  4. Verifica el placeholder: Asegúrate de que el nombre del placeholder (ej. {Scrubbed}) sea lo suficientemente descriptivo para quien revise el Pull Request.

Conclusión

El scrubbing es lo que vuelve usable el snapshot testing en sistemas reales: transforma datos no deterministas (GUIDs, fechas, tokens, valores de entorno) en snapshots estables sin tocar código productivo. La clave es aplicarlo con estrategia: configura scrubbers globales para GUIDs y DateTimes, usa scrubbing de miembros para campos sensibles o dependientes del ambiente, y recurre a RegEx cuando el dinamismo vive dentro de strings o logs. Respeta el orden de los scrubbers para evitar reemplazos “demasiado agresivos” y valida que los placeholders sean claros para quien revise el PR. Bien hecho, el scrubbing reduce ruido, mantiene integridad referencial y convierte los diffs en señales útiles, no en falsas alarmas.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *