El Semáforo de Probar Primero (The Test-First Stoplight, in Spanish)

Los programadores extremos escriben pruebas antes de escribir el código de producción correspondiente. En “La programación de Probar Primero”, se empieza con una pequeña prueba, luego se escribe únicamente el código necesario para pasarla, y se continúa con la siguiente prueba hasta que el código quede terminado.

El Semáforo de Probar Primero

Stoplight: green, yellow, and red La Programación de Probar Primero es como un semáforo. Un semáforo tiene luces verde, amarilla y roja. Empieza con verde, después pasa a azul, luego a rojo y nuevamente a verde. En ocasiones, nos topamos con un semáforo en donde el patrón es diferente, como amarillo intermitente o rojo intermitente. Al ver esto, prestamos más atención y nos preguntamos “¿Qué pasa?”.

Para realizar pruebas en Java, muchos proyectos utilizan la estructura de pruebas JUnit, disponible en www.junit.org. JUnit muestra una barra verde cuando se pasan todas las pruebas y una roja cuando alguna falla. Pensemos en ellas como las luces verde y roja de un semáforo; cuando hay una falla de compilación, la luz es amarilla. Así como en un semáforo normal, debemos esperar que la luz cambie verde, amarillo, rojo; verde, amarillo, rojo.

  1. Inicio. (Luz verde!)
  2. Escribir un prueba.
  3. Intentar ejecutar la prueba.
    La compilación falla porque la función llamada no ha sido escrita todavía. (Luz amarilla!)
  4. Escribir el esqueleto de la nueva función.
  5. Intentar ejecutar la prueba.
    La prueba falla porque el esqueleto todavía no hace nada. (Luz roja!)
  6. Escribir el contenido de la función.
  7. Intentar ejecutar la prueba.
    Se pasa la prueba. (Luz verde nuevamente!)
  8. Iniciar el ciclo nuevamente.

Patrones Anormales

De verde a verde: La prueba pasó sin hacer nada.
Puede que la prueba esté mal diseñada o que ya se haya implementado la característica a probar. Se puede considerar modificar la implementación sólo para ver si la prueba falla. (Ver la sección “Refactoring” más adelante).

De verde a rojo: La prueba falló sin hacer nada.
Esto es normal si es una nueva prueba de una función que ya existe.

De amarillo a amarillo: Ojo – error de sintaxis creando el esqueleto de la función.

De amarillo a verde: La compilación falló sin el esqueleto, pero agregándolo pasó la prueba.
Esta situación es muy sospechosa: Si una función que no hace nada pasa la prueba, ¿la prueba es válida?

De rojo a amarillo: Ojo – error de sintaxis implementando la función.

De rojo a rojo: El nuevo código no funciona.
Esto le puede pasa a cualquier programador de vez en cuando, sólo hay que arreglar el código.
Sin embargo, si esto pasa varias veces, significa que se deberían hacer pruebas más pequeñas (de forma que sólo se agregen pequeñas prociones de código cada vez).

Ciclo Rápido

El ciclo no debe tomar mucho tiempo:

  • escribir la prueba, el esqueleto y el contenido
  • compilar tres veces
  • ejecutar dos veces

Dependiendo del entorno de desarrollo, cada ciclo puede tardar entre uno y cinco minutos. Si un ciclo tarda de 10 a 15 minutos o más, el ciclo está demasiado largo y sería necesario realizar pruebas más pequeñas.

Refactoring

Cuando se hace refactoring, amenudo no se ve cambiar la luz a amarillo o a rojo. Es como esos días en los que se maneja por las calles pasando todos los semáforos en verde.

  1. Inicio. (Luz verde)
  2. Hacer refactoring.
  3. Compilar y ejecutar la prueba. (Luz verde nuevamente!)

Ocasionalmente se puede obtener una luz amarilla o roja, indicando que se debe revisar la sintaxis o se debe ser más cuidadoso con las modificaciones. También puede ser porque al hacer refactoring se está utilizando el compilador para saber si alguna operación es segura o no. Sin embargo, por lo general siempre hay luz verde.

Ejemplo

Veamos un pequeño ejemplo de la programación de Prueba Primero. Supongamos que tenemos un objeto persona como el siguiente:

public class Persona {
    String nombre;
    int favorito = -1;

    public Persona (String nombre, int favorito) {
        this.nombre = nombre;
        this.favorito = favorito;
    }
}

Queremos representarlo en una cadena XML como la siguiente:
<nombre>el-nombre</nombre>
(si favorito es menor que 0), o
<nombre favorito=”nn”>el-nombre</nombre>
si favorito es 0 o más.

  • Iniciamos con luz verde.
  • Creamos la prueba
        Persona p = new Persona("Pa", -1);
    assertEquals("<nombre>Pa</nombre>", p.comoXml());
  • Cuando compilamos obtenemos un error de sintaxis (Luz amarilla!) porque el método comoXml() no existe.
  • Creamos el esquelero del método en la clase Persona:
    public String comoXml() {return null;}
  • Compilamos y ejecutamos; la prueba falla (Luz roja!).
  • Implementamos el método en la forma más sencilla posible:
    public String comoXml() {return "<nombre>" + nombre + "</nombre>";}
  • Compilamos y ejecutamos: luz verde! ciclo completo..
  • Podemos agregar una segunda prueba y observar otra situación:
        Persona p2 = new Persona("Ma", 1);
    assertEquals("<nombre favorito="1">Ma</nombre>", p2.comoXml());
  • Cuando compilamos y ejecutamos, nos saltamos la luz amarilla y vamos directo a la roja. ¿Por qué? Porque comoXml() existe pero no le hemos agregado la funcionalidad esperada.
  • Implementamos el código necesario y obtenemos luz verde nuevamente.

Conclusión

Observar el semáforo mientras se codifica hasta que un patrón anormal nos dé una pequeña punzada.

Articulos Relacionados

[Escrito 1-2-2001, William C. Wake]The Test/Code Cycle in XP: Part 2, GUI
[Traducido al español 11-04-2003, Diego SantaTES America]