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
Excelente, me sirvio mucho para el TDD
Me gustaMe gusta
Me alegro de que te sirviese, si tienes alguna sugerencia será bienvenida 😉
Me gustaMe gusta
Hola, justamente estaba formándome en TDD y me ha parecido muy buen aporte, sigue así! 🙂
Me gustaMe gusta