Leer la función invocada, probar al culpable
Una corrección cuya prueba unitaria pasa en verde puede quedar anulada, en la misma vuelta de ejecución, por la función invocada justo después, y la función ya corregida solo es un culpable probado una vez que una prueba ha aislado su efecto del de las funciones siguientes.
Una corrección que arregla exactamente la función culpable, con una prueba unitaria que pasa en verde, puede no cambiar nada de lo que ve el usuario. La causa se reduce a una sola cosa: la función que acabas de corregir casi nunca es la última en tocar el valor. El resultado corregido pasa todavía, en la misma vuelta de ejecución, por una o varias funciones invocadas justo después, y una de ellas puede anular la corrección sin que ninguna prueba lo señale.
La corrección que no sobrevive a la siguiente llamada
Toma un caso fabricado para sostenerse solo, sin depender de ningún archivo del proyecto. La función formatPrice redondeaba mal un precio en céntimos, la corrección hace que ahora redondee a dos decimales. Su propia prueba pasa. El precio mostrado en pantalla sigue siendo falso, sin embargo, porque una función aplicada justo después, applyDiscount, vuelve a convertir ese texto en número y lo redondea una segunda vez hacia abajo.
function formatPrice(cents) {
return (cents / 100).toFixed(2); // corregido: dos decimales exactos
}
function applyDiscount(priceText) {
const price = parseFloat(priceText);
return Math.floor(price * 0.9); // redondea de nuevo, hacia abajo
}
console.log(formatPrice(1299)); // 12.99, la correccion funciona sola
console.log(applyDiscount(formatPrice(1299))); // 11, la correccion queda anulada
La primera llamada prueba que formatPrice es correcta. La segunda llamada, la que realmente llega a la pantalla, prueba lo contrario. Una corrección se prueba sobre esta segunda cifra, nunca sobre la primera.
El culpable plausible no es el culpable probado
Ante una pantalla que sigue mostrando un valor falso después de una corrección, la función ya modificada vuelve a ser el primer sospechoso. Es un culpable plausible, no un culpable probado. Para decidir, lee las primeras y las últimas instrucciones de cada función invocada justo después de la que acaba de corregirse, no solo la función en sí. En el ejemplo, la última instrucción de applyDiscount, Math.floor, es la línea que borra los céntimos que formatPrice acababa de restituir.
La prueba final no se lee en el código, se lee en una salida. Escribe una prueba que aísle exactamente la entrada y la salida visibles en pantalla, en este caso el valor que devuelve applyDiscount, y lee lo que esa prueba realmente devuelve antes de señalar a un culpable. Es el mismo principio que verificar el estado real antes de actuar sobre una solicitud: una corrección se establece sobre el resultado producido, nunca sobre la lectura del código que se supone lo produce.
Cuando el culpable sigue sin determinarse
Dos funciones invocadas en la misma vuelta pueden modificar cada una el mismo valor de una manera que produce, por separado, un resultado plausible. Una prueba que no separe sus efectos no zanja nada. En ese caso, la respuesta correcta no es elegir una función al azar para cerrar el tema: consiste en escribir dos pruebas distintas, una por función sospechosa, aislando cada una de la otra, y luego decir que la identidad del culpable sigue sin determinarse mientras esas dos pruebas no se hayan ejecutado y leído.
De la corrección aplicada al veredicto zanjado
Un desarrollador corrige la función que redondea un precio mostrado, su prueba unitaria pasa en verde, luego vuelve a lanzar la aplicación y sigue viendo un precio mal redondeado en pantalla.
Escribe en una frase lo que esta situación establece, y en una frase lo que no establece.
Lo que esto establece: La corrección aplicada a la función de redondeo no bastó para hacer desaparecer el mal redondeo visible en pantalla.
Lo que esto no establece: No establece que la función corregida siga siendo culpable, ya que el precio mostrado puede haber sido retocado por una función invocada después de ella.
Los tres calibrados falsos más frecuentes
- Demasiado amplio Toda función corregida en esta aplicación produce un resultado que sigue mostrándose como erróneo en pantalla.
- Demasiado estrecho Esta constatación solo afecta a este lanzamiento concreto de la aplicación y no se repetirá si se relanza una segunda vez.
- Fuera de lugar La prueba unitaria de la función de redondeo ahora cubre todos los casos de precio que la aplicación puede encontrar.
- Una corrección cuya prueba unitaria pasa en verde no garantiza nada en pantalla si una función invocada justo después vuelve a tocar el mismo valor.
- Leer solamente la función que se acaba de corregir deja invisible todo lo que ocurre en las funciones siguientes de la misma vuelta de ejecución.
- Un culpable plausible sigue siendo una hipótesis mientras una prueba no haya aislado su entrada y su salida exactas.
- La prueba de una corrección se encuentra en la salida que devuelve la prueba, no en una relectura del código que se supone la produce.
- Cuando dos funciones sospechosas modifican el mismo valor de forma plausible cada una, la respuesta honesta es decir que el culpable sigue sin determinarse mientras dos pruebas distintas no las hayan separado.
Retoma una corrección que hayas aplicado recientemente sin revalidarla con una prueba aislada, escribe una función desechable de unas pocas líneas que reproduzca el encadenamiento exacto entre la función corregida y la que la invoca después, luego ejecuta esa prueba y lee su salida antes de seguir confiando en la corrección.