Background Image
DESARROLLO DE SOFTWARE

Pruebas basadas en el contexto en la vida de Don Testa'lot Moore

June 2, 2021 | 3 Minuto(s) de lectura

Varios desarrolladores y organizaciones abandonan ciertas prácticas de pruebas automatizadas porque las pruebas se vuelven frágiles y difíciles de mantener.

Echemos un vistazo a la vida de nuestro personaje ficticio Don, el carismático desarrollador hijo de la Sra. Aido Test'alot y el Sr. Telme Moore. En su trabajo actual, Don Testa'lot Moore ha seguido un curso de "Introducción a las pruebas unitarias" y ha aprendido sobre marcos de pruebas y ejecutores de pruebas. Se vuelve "loco por las pruebas unitarias" y escribe varias pruebas para una clase que está creando. Se siente muy bien al ver la alta cobertura de código conseguida con esas pruebas. Los compañeros de equipo están intrigados por el gran trabajo realizado por el lote del Sr. Testa Moore, y él organiza con gusto una reunión para compartir sus nuevos conocimientos con el equipo.

Muestra las pruebas a sus compañeros de trabajo, explicándoles que las pruebas viven en un fixture de pruebas. Cada prueba está organizada siguiendo la plantilla "arrange-act-assert" (también conocida como AAA). Sus expresiones faciales muestran preocupación al ver cientos de líneas de código en el archivo; muchas más líneas de código que la propia clase que se está probando. "Eso es mucho esfuerzo", dice una persona, "y me temo que el jefe también lo pensará".

Semanas después, se encuentra un defecto. La solución es fácil: un simple bloque if se encargará de todo. Pero el Sr. Testa'lot Moore ha aprendido que primero hay que escribir una prueba unitaria que reproduzca el defecto. Navega por la larga lista de pruebas tratando de encontrar una que parezca un buen punto de partida para la nueva prueba. Resulta ser una tarea difícil, ya que varias pruebas se parecen mucho. Se decide por una de ellas, la copia y pega y procede a hacer los ajustes necesarios para que reproduzca el defecto notificado. Cuando termina, mira los cambios en el código y se da cuenta de que hay 50 nuevas líneas de código de prueba para una línea de código de implementación (un simple uso del operador ternario hizo el truco).

Tanto los compañeros de equipo como la jefa se dieron cuenta del tiempo que se tardaba en corregir el defecto y llamaron a su desarrollador a su despacho para hablar con él y decirle que no que no perdiera tanto tiempo en el futuro. Después de ese golpe, el desarrollador tiene que dejar su práctica recién descubierta, así que ahora el lote Moore del Sr. Don Testa cuestiona su confianza en entregar código sin pruebas automatizadas adecuadas. Para su alivio, un mentor entra en su vida y le proporciona la orientación que necesita.

Esto es lo que Don escucha de su mentor...

Tomemos Cuenta bancaria para la que has escrito muchas pruebas. Tienes un fichero de pruebas llamado BankAccountTestsque contiene todas las pruebas para esa clase. Veo casi 1.000 líneas de código ahí. La clase BankAccount tiene varios métodos, entre ellos Depositar, Retirary TransferirFondos. El fixture incluye al menos una prueba para cada método, y la mayoría de los métodos requieren múltiples pruebas para verificar las diferentes ramas que se ejecutan en función de los parámetros introducidos. También hay pruebas que verifican casos excepcionales.

Bank account test fixture

El primer paso para mejorar estas pruebas es organizar el fixture agrupando las pruebas para los mismos métodos, de forma que podamos ver todas las pruebas para el método Deposit juntas, así como para Withdraw, TransferFunds, etc.

A continuación, cree un archivo BankAccountSpecs (sí, vamos a empezar a pensar en esas cosas como especificacionesen lugar de pruebas). Mueva la carpeta BankAccountTests allí.

Ahora, cree un archivo para cada método que esté probando. Simplemente copie el archivo BankAccountTests y péguelo tantas veces como sea necesario. Una buena forma de nombrar esos archivos es Depositando, Retirar, TransferirFondosetc. Entre en cada archivo y elimine todas las pruebas que no sean las del método respectivo que se está probando.

Bank account specs

Sólo ese cambio ya produce beneficios. La próxima vez que tenga que hacer algo a la clase BankAccount en el contexto del depósito, podrá centrarse sólo en las pruebas de esa área.

Sigamos, elijamos uno de esos contextos. Digamos, Depósito, ya que acabamos de mencionarlo. Fíjate en el método organizar de cada prueba. Identifica lo que tienen en común. Encuentra código que se vea exactamente exactamente igual en algunas pruebas. Extraiga ese código en métodos separados y reutilícelo en todas las pruebas. Busque código que parezca en su mayor parte el mismo, excepto por cosas menores (tal vez hay un método verdadero y un valor falso allí). Extraiga esas líneas en un método separado, convierta esos valores variables en parámetros y reutilice el método donde corresponda. Siga el mismo proceso con el método act y assert de cada prueba. El archivo debería tener ahora muchas menos líneas de código y cada prueba debería ser mucho más agradable. Haga lo mismo con los archivos de prueba de los demás métodos.

Cuando todos los archivos de prueba hayan sido limpiados, revíselos, mire los métodos que creó para manejar las secciones arrange, act y assert, encuentre los métodos que se ven exactamente igual en todos los archivos, córtelos y péguelos en un nuevo archivo llamado BankAccountSpecsBase (o algo así). ¿Adivine qué? Sí, ¡reutiliza el código de tus archivos de especificaciones! Si están escritos en un lenguaje que soporta herencia (C#, TypeScript, Java), acabas de obtener una clase base para tus especificaciones BankAccount. En lenguajes que no soportan herencia, sólo tienes un módulo, o cualquier mecanismo a tu disposición para reutilizar código.

Sigue revisando esos archivos e identifica cualquier otro código que se pueda utilizar en las especificaciones. Al final de este proceso, comprenderás mejor las cosas. Por ejemplo, usted puede encontrar que la clase BankAccount es siempre se instancia de la misma manera. O puede que se instancie de la misma manera en función del método está siendo llamado (como inicializado con un saldo inicial de $0 cuando se prueba el método Deposit, y un saldo inicial de $1000 en pruebas para el método Withdraw).

En este punto, eche un vistazo a cada archivo de especificaciones de nuevo. Volvamos a retirarpor ejemplo. Mira a través de sus pruebas y ver si hay algún código redundante a través de ellos. En este momento, cualquier cosa que quede allí debe ser específica para retirar. Todavía puede haber una docena de pruebas en el archivo. ¿Puedes adivinar lo que viene a continuación? Cree una carpeta llamada retirando y mueve allí el archivo de especificaciones. Identifique qué pruebas tienen características similares organiza son contextos específicos en los que se producen retiradas. Agrúpelas y muévalas a archivos separados con el nombre del contexto (por ejemplo, "importe no válido", "fondos insuficientes", "línea de crédito disponible", "víctima de fraude marcada"). Revisa esos archivos, identifica cualquier código común, sácalo y pégalo en un nuevo archivo llamado WithdrawingContext (o algo parecido).

Bank account specs 2

¿Qué conseguimos con este método?

  • Archivos de especificaciones muy pequeños y fáciles de entender;

  • La organización por contexto hace que sea más fácil encontrar las especificaciones según sea necesario (

    "hmm, se ha encontrado un defecto al retirar dinero de una cuenta bancaria que ha sido marcada como víctima de fraude. Sé exactamente cómo encontrar inmediatamente las pruebas en ese ámbito". );

  • Escribir nuevas especificaciones es mucho más fácil porque hay mucho "código de prueba" que se puede reutilizar;

  • A partir de aquí, las nuevas especificaciones para cualquier área se escriben con este proceso de pensamiento en mente (

    "¿Cuáles son los escenarios? ¿Cuáles son los contextos? ¿En qué se parecen o en qué se diferencian?");

  • Cuando se hacen cambios en el código y las pruebas fallan, ahora es más rápido ver las características y los escenarios afectados por los cambios;

  • El enfoque funciona independientemente del tipo de pruebas (unitarias, de integración, de extremo a extremo), de la parte del software (front-end, back-end), de los marcos de pruebas y de los ejecutores (MS-Test, NUnit, JUnit, xUnit, Jest, Jasmine, Cypress.io...);

  • Las pruebas no se pudrirán ni se abandonarán, ya que ahora están limpias, bien organizadas y son más fáciles de mantener.

Después de esta experiencia de iluminación con su mentor, Don decide abandonar su nombre de pila y ¡ahora sólo se hace llamar Sr. Testa'lot!

Desarrollo de software

Reflexiones más recientes

Explore las entradas de nuestro blog e inspírese con los líderes de opinión de todas nuestras empresas.
Tomorrow Technology Today Blog Thumbnail
IA/ML

Ingeniería de plataformas de IA escalables: Estrategias de sostenibilidad y reutilización

Cómo construir plataformas de IA escalables que garanticen la sostenibilidad, la colaboración y la eficiencia en su organización.