Empezando con TDD – Primer ejemplo paso a paso

Ya lo tenemos todo instalado, xammp funcionando, eclipse pdt con el plugin de phpunit y hemos probado que todo funciona correctamente con un pequeño ejemplo. Ahora vamos con lo divertido.

Para recordarlo vamos a resumir en un momento esto del TDD

Test Driven Development (TDD)

TDD es una técnica para desarrollar y diseñar software. Consiste en escoger un requisito a desarrollar y aplicar estas reglas.

1 No escribir código ninguno, escribir primero una prueba (test)para el requisito.
2 Verificar que la prueba falla.
3 Escribir el código para pasar la prueba.
4 Ejecutar la prueba y comprobar que el código funciona.
5 Refactorizar el código para evitar duplicación.

Aserciones

Antes de entrar en materia, debemos conocer las aserciones, cada vez que escribimos n test debemos comprobar si se cumple una condición. Para ello PHPUnit nos provee de una serie de funciones llamadas asserts.

En la Wikipedia podemos ver que una aserción es un predicado (i.e., una sentencia verdadero-falso) incluido en un programa como indicación de que el programador piensa que dicho predicado siempre se cumple en ese punto del flujo de programa.

Aquí la tabla con las aserciones que se pueden utilizar en PHPUnit http://phpunit.de/manual/3.6/en/appendixes.assertions.html, pero no debemos preocuparnos no hay nada que “crtl + espacio” (autocompletado) no pueda solucionar 😉

Ejemplo de la cuenta bancaria

La mejor manera de aprender TDD es practicando, así que vamos a realizar una pequeña introducción utilizando un ejemplo.

Imaginemos que tenemos que implementar un banco, lo más importante del banco son las cuentas de sus clientes, así que tenemos estos requisitos.

El saldo inicial de la cuenta debe ser 0
El saldo de la cuenta no puede ser negativo

Así que manos a la obra.

Crear el proyecto

Lo primero de todo es tener el workspace de eclipse en C:\xampp\httdocs ahora lo que hacemos es crear un nuevo proyecto llamado “CuentaBancariTDD” y creamos una carpeta para guardar los tests.

Ahora escogemos el requisito el saldo inicial de la cuenta debe ser 0. Y vamos a crear el primer test

Requisito 1: el saldo inicial de la cuenta debe ser 0

Creando el 1º test

Si analizamos el requisito el saldo inicial de la cuenta debe ser 0, vemos que tenemos que ser capaces de crear una cuenta, es decir crear un objeto o algo de tipo cuenta. También debemos ser capaces de obtener el saldo disponible en dicha cuenta. Bien, llegados a este punto vamos a crear un test que cree un nuevo objeto cuenta y vamos a hacer un assert para comprobar que el estado justo después de crear el objeto es 0;

Aquí tenemos el código:

<?php
       require_once '/../src/CuentaBancaria.php'; 
       class   CuentaBancaria_Test   extends   PHPUnit_Framework_TestCase
       {
             public   function   testBalanceIncialEsCero ( )
             {
                    $this -> cb = new CuentaBancaria();
                    $this -> assertEquals ( 0 ,   $this -> cb -> getBalance ( ) ) ;
             }
       }

Probando que falla

Ahora siguiendo las indicaciones vemos que el test falla. Pero llegados a este punto y solo con un test hemos decidido muchas cosas, métodos, parámetros devueltos por los métodos, como va a organizarse nuestro código…

Creando el código

Ahora tenemos que crear el código necesario para pasar la prueba. Crearemos una nueva clase donde llamada cuenta bancaria con la que podremos crear una cuenta. Esta clase de momento tendrá solamente una función que devuelve el balance de la cuenta.

Ya tenemos creado nuestro código:

<?php
class CuentaBancaria
{  
       protected $balance = 0;     
       public function getBalance()
       {
             return $this -> balance;  
       }
}

Ahora el test funciona

Solo nos queda probar que todo está correcto, para ello ejecutamos el test. Como vemos con “require_once” hemos creado una nueva carpeta llamada src donde albergamos el código de la clase Cuenta bancaria.

Refactor

De momento no hay mucho por refactorizar, así que vamos a por el siguiente requisito.

Requisito 2: El saldo de la cuenta no puede ser negativo

Bueno pues vamos a la carga con el 2º requisito.

Creando el test

Podemos ver que para que el saldo sea negativo, debemos implementar un mecanismo (función) para retirar dinero de la cuenta. Por otro lado vamos a probar las excepciones, es decir, si intentamos sacar dinero teniendo la cuenta 0 vamos a tener una excepción ya que se incumple un requisito. Básicamente este es el código:

public   function   testBalanceNoPuedeSerNegativo ( )
             {
                    $this -> cb = new CuentaBancaria();
                    try   {
                           $this -> cb -> retirarDinero ( 1 ) ;
                    }            
                    catch   ( Exception   $e )   {
                           $this -> assertEquals ( 0 ,   $this -> cb -> getBalance ( ) ) ;
                           return ;
                    }                   
             }

Probando que falla

Ahora ejecutamos el test y vemos que falla.

Creamos el código

Vamos a crear 2 funciones, una para depositar dinero y otra para comprobar que el balance de la cuenta sigue siendo mayor que cero.

protected   function   setBalance ( $balance )
       {
             if   ( $balance   >=   0 )   {
                    $this -> balance   =   $balance ;
             }   else   {
                    throw   new   Exception();
             }
       }    
       public   function   depositarDinero ( $balance )
       {
             $this -> setBalance ( $this -> getBalance ( )   +   $balance ) ;
             return   $this -> getBalance ( ) ;
       }

Pasar el test

Comprobamos que ahora el test pasa.

Refactorizar

Esta es una de las cosas más difíciles, ya que hay que darse cuenta del código duplicado. Podemos ver que en cada uno de los tests estamos creando una nueva cuenta bancaria. Podríamos crear un método setup que se ejecute antes de nuestros tests. En este método setup lo que podemos hacer es crear el entorno, en nuestro caso crear la cuenta bancaria. Así que allá vamos.

Así quedaría nuestra clase de test:

<?php
       require_once '/../src/CuentaBancaria.php';
       class   CuentaBancaria_Test   extends   PHPUnit_Framework_TestCase
       {
             protected $cb;
              protected function setUp()
             {
                    $this -> cb = new CuentaBancaria();
             }

             public   function   testBalanceIncialEsCero ( )
             {                 
                    $this -> assertEquals ( 0 ,   $this -> cb -> getBalance () ) ;
             }
             public   function   testBalanceNoPuedeSerNegativo ( )
             {
                    try   {
                           $this -> cb -> depositarDinero ( 1 ) ;
                    }
                   catch   ( CuentaBancariaException   $e )   {
                           $this -> assertEquals ( 0 ,   $this -> cb -> getBalance ( ) ) ;
                            return ;
                    }
             }
       }

Por otro lado también refactorizaremos el código, en nuestro caso de momento no hay nada que refactorizar. Aunque debemos darnos cuenta de que esto no está acabado, podemos depositar dinero, pero ¿y retirarlo? Todavía nos falta crear un test para que el requisito 2 se cumpla.

Este es el test:

public function testBalanceNoPuedeSerNegativo2()
             {
                    try   {
                           $this -> cb -> retirarDinero ( 1 ) ;
                    }
                    catch   ( Exception   $e )   {
                           $this -> assertEquals ( 0 ,   $this -> cb -> getBalance ( ) ) ;       
                           return 0 ;
                    }
             }

Comprobamos que no pasa:

Creamos el código:

public function retirarDinero ( $balance )
    {
          $this -> setBalance ( $this -> getBalance ( )   -   $balance ) ;
          return   $this -> getBalance ( ) ;
    }

Y vemos que ya pasa el test ya si pasa

Referencias

Basado en el ejemplo de PHPUnit http://phpunit.de/manual/3.6/en/test-driven-development.html

Anuncios

3 comentarios en “Empezando con TDD – Primer ejemplo paso a paso

Comenta la entrada

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s