TDD - Pruebas de unidad con PHPUnit
En esta entrada quiero enseñarte con un ejemplo como hacer pruebas de unidad con PHPUnit. e instalarlo en Ubuntu.
Pero primero una pequeña introducción por si estás perdido ...
¿Qué es TDD ?. Si alguien puede explicar mucho mejor que yo qué es TDD , pues ese es Carlos Ble y su libro Diseño Ágil con TDD ya que yo practicamente estoy introduciéndome en el mundillo ya que TDD son muchas cosas . Pero en pocas palabras, TDD es hacer los test de tus funciones y luego codificar la función en sí.
TDD es una disciplina , es cambiar tu manera de programar de siempre.
Hacer TDD con PHPUnit es hacer una batería de pruebas de unidad (test) , para todas las funciones de tu programa y en caso de que alguna no supere la prueba, PHPUnit te avisará y sabrás que hay algo mal en tu código, en el sentido de que la función no devuelve lo esperado para el test.
Podrás decir ... "Vaya rollo ! ¿No tengo poco trabajo con programar el código ,sino que encima me estás diciendo que haga una prueba de unidad antes de codificar cada función que necesite ???". Pues sí .
El tiempo que "pierdes" haciendo las pruebas, lo estás ganando en que si el test pasa como válido , es que tu función hace lo que tiene que hacer y por ejemplo , no te llamarán por teléfono diciendote ... "Oye , que estoy encriptando las claves de los usuarios con la función aquella que hiciste y esto no va ... no pueden loguearse ... , mira a ver que hiciste !! " .
Por no haber hecho pruebas ... ahora , tienes que buscar el problema, que a lo mejor solucionas rápido ( o no), pero el "mal trago" y el tiempo perdido arreglando la función , no te lo quita nadie.
Pues para que no te pase más esto , están las pruebas de unidad, para todo lo demás , Master Card ;).
Para no aburrirte mucho leyendo voy a pasar a como instalar PHPUnit , y cómo usarlo en tus proyectos php con Composer.
Cómo instalar PHPUnit
PHPUnit es un framework que te permite hacer pruebas de unidad en php, es decir , tus test. Para instalarlo , simplemente tienes que seguir la documentación del proyecto en GitHub , pero para ahorrarte el trabajo , aquí te escribo lo que tienes que hacer, eso sí , en Linux.
Descargar PHPUnit:
wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit
¿Qué hacen esos comandos ?
Pues con wget descargas el script .phar PHPUnit , luego le damos permisos de ejecución y finalmente lo movemos a nuestra carpeta /usr/local/bin , ya que en Ubuntu, en esa ruta podemos poner scripts y podrás acceder a ellos desde cualquier ruta del disco.
¿ Ya está ? , sí , ya tenemos el script PHPUnit en el sistema.
Manos a la obra.
Bien , ¿ Qué mejor que empezar con un ejemplo ? , quiero ponerte un ejemplo útil , no el típico ejemplo de la calculadora , sumar , restar , multiplicar y dividir , para que puedas ver la importancia de las pruebas de unidad. Por un lado quiero explicarte como descargar composer para crear un archivo composer.json y por otro cómo descargar las dependencias para realizar nuestro objetivo.
Primer paso: Descargar Composer.
Para ello puedes ir a la página oficial o ejecutar este comando ( te lo dirán en la página )
curl -sS https://getcomposer.org/installer | php
Con ello descargarás la útima versión de composer en el directorio donde ejecutes el comando.
Si quieres utilizar composer desde cualquier sitio , como con PHPUnit , muévelo con :
mv composer.phar /usr/local/bin/composer
Una vez ahí ya podrás utilizarlo desde cualquier sitio.
Segundo paso: Crear el fichero composer.json para descargar las dependencias.
Para que composer pueda descargar las dependencias de PHPUnit necesita un archivo que se tiene que llamar composer.json , y su contenido será un JSON donde pondremos las dependencias a descargar.
composer.json
{
"require-dev": {
"phpunit/phpunit": "4.0"
}
}
Tercer paso: Descargar las dependencias.
Para descargar las dependencias , tenemos que situarnos en la carpeta de nuestro proyecto, donde tengamos el composer.json y ejecutar simplemente:
composer update
y se descargarán las dependencias.Cuarto paso: El proyecto de ejemplo !
Crea una carpeta en tu /var/www llamada phpunit ( por ejemplo ) y los siguientes archivos: (También puedes descargar el proyecto de ejemplo en NetBeans en mi Github https://github.com/tsw1985/PHPUnit ).
index.php donde ahí llamaremos a la función incrementSalary() , en este caso solamente vamos a ver un "echo" de la salida de la función.
functions.php , ahí tendremos nuestras funciones para nuestro programa.
phpunit,xml , este será el archivo de configuración donde indicaremos en que carpeta están nuestros tests unitarios, y que queremos ver los resultados en color ,para ver mejor si se han superado los test o no.
Una carpeta llamada "test" y dentro este archivo MyTest.php , ésta será la clase que ejecutará nuestros test.
1: <?php
2: $actualSalary = 1000;
3:
4: require_once('./functions.php');
5: echo "El aumento de un 2% del sueldo de ".$actualSalary." Euros es ".incrementSalary( $actualSalary)." Euros";
6: ?>
functions.php
1: <?php
2: function incrementSalary( $actualSalary ){
3: return ( 2 * $actualSalary ) / 100;
4: }
5: ?>
test/MyTest.php
1: <?php
2: require_once 'functions.php';
3: class MyTest extends PHPUnit_Framework_TestCase
4: {
5: public function testIncrementSalary()
6: {
7: $incrementSalary = incrementSalary( 1000 );
8: $this->assertEquals( 20, $incrementSalary );
9: }
10: }
11: ?>
phpunit.xml
1: <?xml version="1.0" encoding="UTF-8"?>
2: <phpunit colors="true">
3: <testsuites>
4: <testsuite name="Application Test Suite">
5: <directory>./test</directory>
6: </testsuite>
7: </testsuites>
8: </phpunit>
Ya con esto , tenemos lo necesario para realizar las pruebas . Ten en cuenta que para que PHPUnit encuentre los test unitarios, el nombre de las funciones deben empezar por "test".
Si ejecutamos en la raiz del proyecto :
phpunit
Veremos que los test son válidos. Las funciones se ejecutan bien y devuelven lo esperado.
¿Cómo funcionan los test?
La clase MyTest.php extiende de PHPUnit_Framework_TestCase donde están todos los métodos asserts. Podemos tratar excepciones y muchas más cosas con ellos. Aquí tienes el listado de los assertions.
Assert en inglés significa "acierto","afirmación","coincidencia" y como su nombre indica , el método assertEquals comprobará si coincide un valor que conocemos previamente , con el valor que debe devolver la función.
$incrementSalary = incrementSalary( 1000 );
$this->assertEquals( 20, $incrementSalary );
El test almacenará en la variable $incrementSalary el resultado que devuelve nuestra función, que es 20. Y el método assertEquals() está diciendo: "En mi primer parámetro sé que tengo que tener un 20 , y en el segundo parámetro tendré el resultado. Si es algo distinto a 20 , pues daré este test por negativo".
El test negativo.
A la función le ponemos el 20%.
El test unitario sigue esperando un 20.
Vemos como PHPUnit nos avisa del error, esperaba 20 y obtuvo 200.
Conclusión.
Como has visto , este test ha dado positivo. Ahora imagina por un momento , que la función incrementSalary() la refactorizas , o alguien pone que se haga el cálculo con un 20% en vez de con un 2% y ese código va a producción. Como ya has adivinado , el cálculo se hará mal, los salarios aumentarán en un 20% en vez de en un 2%.
El test negativo.
Como iba diciendo, vamos a cambiar el comportamiento de la función para ver como PHPUnit nos dice que hay una función que no pasa el test. Eso sí, si realmente quieres cambiar su comportamiento , en la función de test tienes que cambiar el valor esperado ya que realmente estas refactorizando la función original, pero en el supuesto caso de que no la quieras cambiar, pues el test unitario te avisa del error.
1: <?php
2: function incrementSalary( $actualSalary ){
3: return ( 20 * $actualSalary ) / 100;
4: }
5: ?>
El test unitario sigue esperando un 20.
$incrementSalary = incrementSalary( 1000 );
$this->assertEquals( 20 , $incrementSalary );
Vemos como PHPUnit nos avisa del error, esperaba 20 y obtuvo 200.
Conclusión.
PHPUnit ha realizado los test y nos está diciendo : "En el test de unidad testIncrementSalary de la clase MyTest , estaba esperando un 20 y la función me ha dado 200, esto no coincide , por lo tanto no pasa el test".
Aquí ya vemos la importancia de los test unitarios, sobre todo para funciones importantes como éstas (en el supuesto caso de que fuera un programa real y un proyecto grande en el que trabajan muchos programadores).
En este ejemplo es una función muy cortita , pero el caso se puede dar en la realidad , con otras funciones importantes que realizan cálculos , encriptación ... o cualquier otra cosa. Lo suyo es tener pruebas unitarias a todas las funciones del código.
PHPUnit cubre muchas más funcionalidades, pero yo en esta entrada solamente quería centrarme en las pruebas de unidad , en como se instala PHPUnit en Ubuntu con Composer, ya que yo practicamente estoy iniciándome en el TDD.
Si quieres saber mucho más sobre las posibilidades que ofrece PHPUnit , aquí tienes la documentación.
Y nada más que añadir, según vaya aprendiendo más sobre TDD iré haciendo más entradas para explicar lo que haya aprendido para intentar ayudar a otros que también estén iniciándose y hacerles el camino un poco más fácil si no saben por donde empezar.
También quise escribirlo lo más claro posible, de manera que si alguien no tiene ni idea de pruebas unitarias que entienda los conceptos de una manera fácil.
Espero que este post te haya servido de ayuda ;).