Un fallo en uso es la mejor prueba
Una evaluación desde producción convierte un fallo real en un caso de prueba. Sirve porque los clientes encuentran fallos que nadie previó, pero sus mensajes llevan nombres, direcciones y números que no debes guardar.
El agente de la tienda falla cuatro veces esta semana. ¿Qué partes de esos chats pueden entrar en tu conjunto de pruebas?
Al final de esta lección
Nota
Puedo convertir un fallo en uso en un caso sin guardar lo que no debe guardarse.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Traza | el registro de una ejecución real |
| Ocultado | cambiar un dato personal por una marca |
| Muestreo | elegir qué trazas mirar |
| Caso de control | una traza que pasa y se guarda para ver qué no debe romperse |
| Deriva | un conjunto que cambia hasta que ya no mide lo mismo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Elige qué trazas leer
No puedes leer cada traza. El muestreo elige. Toma cada fallo que informó un usuario o marcó una comprobación. Añade unas pocas trazas que pasan como casos de control, para que una corrección no rompa lo que funcionaba.
Un fallo solo es un caso cuando una persona ha escrito lo que debía pasar.
Ejemplo resuelto: seis trazas dan cuatro casos
| Traza | Resultado | Qué pasa con ella |
|---|---|---|
| t1 | fallo | un caso, con el correo sustituido |
| t2 | ok | un caso de control |
| t3 | fallo | un caso, con el teléfono sustituido |
| t4 | fallo | un caso |
| t5 | fallo | descartada: misma entrada que t4 una vez ocultada |
| t6 | ok | no muestreada |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Quita los datos personales antes de guardar
El ocultado cambia cada nombre, dirección y número por una marca como [correo]. Hazlo con reglas que puedas leer y probar, nunca pidiéndoselo a un modelo, y oculta también el texto esperado.
Después comprueba. Busca en los casos terminados lo que debería haber desaparecido. Un caso que aún tiene una dirección es una fuga de datos en tu conjunto de pruebas.
Evita que el conjunto derive
La deriva significa que el conjunto cambia en silencio hasta que una puntuación del mes pasado ya no significa lo mismo. Dale al conjunto una versión. Añade casos solo tras revisarlos, nunca con un script que se ejecute cada noche.
Pon un límite a su tamaño y descarta duplicados, para que una avalancha de un solo fallo no pese más que el resto.
Escribe las trazas grabadas, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Trazas inventadas de un agente de tienda. Las personas y los números son falsos.' 'const traces = [' ' { id: \"t1\", outcome: \"failed\", user: \"Reembolsa el pedido A17, mi correo es [email protected]\", expected: \"Preguntar qué artículo y reembolsar una sola vez\" },' ' { id: \"t2\", outcome: \"ok\", user: \"¿Dónde está el pedido B02?\", expected: \"Decir que está enviado\" },' ' { id: \"t3\", outcome: \"failed\", user: \"Llámame al +34-612-345-678 por el pedido C11\", expected: \"Ofrecer la página de ayuda, no prometer llamada\" },' > traces.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe las trazas grabadas, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' { id: \"t4\", outcome: \"failed\", user: \"¿Dónde está mi paquete? [email protected]\", expected: \"Buscar el pedido y pedir el número\" },' ' { id: \"t5\", outcome: \"failed\", user: \"¿Dónde está mi paquete? [email protected]\", expected: \"Buscar el pedido y pedir el número\" },' ' { id: \"t6\", outcome: \"ok\", user: \"Hola\", expected: \"Saludar al cliente\" },' '];' 'module.exports = { traces };' >> traces.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el constructor de casos, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { traces } = require(\"./traces\");' 'function redact(text) {' ' return text.split(\" \").map(function (word) {' ' let core = word;' ' let tail = \"\";' ' while (core.length > 0 && \".,?\".includes(core[core.length - 1])) {' ' tail = core[core.length - 1] + tail;' ' core = core.slice(0, -1);' ' }' ' if (core.includes(\"@\")) return \"[correo]\" + tail;' ' const digits = core.split(\"\").filter(function (c) { return c >= \"0\" && c <= \"9\"; }).length;' ' const plain = core.split(\"\").every(function (c) { return (c >= \"0\" && c <= \"9\") || c === \"+\" || c === \"-\"; });' ' if (plain && digits >= 7) return \"[teléfono]\" + tail;' ' return word;' ' }).join(\" \");' '}' > cases.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el constructor de casos, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const seen = [];' 'const cases = [];' 'const dropped = [];' 'let okSeen = 0;' 'traces.forEach(function (trace) {' ' const made = { input: redact(trace.user), expected: redact(trace.expected), source: trace.id };' ' if (trace.outcome === \"ok\") {' ' if (okSeen % 2 === 0) { made.kind = \"control\"; cases.push(made); }' ' okSeen = okSeen + 1;' ' return;' ' }' ' if (seen.includes(made.input)) { dropped.push(trace.id); return; }' ' seen.push(made.input);' ' made.kind = \"fallo\";' ' cases.push(made);' '});' >> cases.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el constructor de casos, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'cases.forEach(function (one, at) {' ' console.log(\"Caso \" + (at + 1) + \" (\" + one.kind + \", de \" + one.source + \"): \" + one.input);' '});' 'console.log(\"Descartado por duplicado: \" + dropped.join(\", \"));' 'const left = cases.filter(function (one) { return one.input.includes(\"@\") || one.input.includes(\"612\"); });' 'console.log(\"Casos que aún tienen datos personales: \" + left.length);' 'console.log(\"Conjunto versión 1 con \" + cases.length + \" casos\");' >> cases.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Construye casos desde las trazas
docker exec -w /home/node/project agent node cases.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lo que imprime el constructor
| Línea | Lo que muestra |
|---|---|
| Casos 1 a 4 | tres fallos y un control, con los datos personales sustituidos |
| Descartado | t5 |
| Datos personales que quedan | 0 |
| Conjunto | versión 1 con 4 casos |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Pruébalo
Consejo
En traces.js añade una traza cuyo texto lleve una dirección como [email protected] y lanza otra vez. El caso debe mostrar [correo]. Después quita la llamada a redact y mira qué se filtra.
Un error frecuente
Advertencia
Mucha gente oculta solo el mensaje del usuario. El texto esperado, el id de la traza y los argumentos de las herramientas pueden llevar la misma dirección. Oculta cada campo que guardes, o guarda solo los que necesitas, y prueba el conjunto terminado para ver lo que debería haber desaparecido.