TDD con PHP gracias a PHPUnit

0
25941

Creación: 04-03-2012

Índice de contenidos

1. Introducción
2. Entorno
3. Como instalar PHP
4. Como instalar PEAR
5. Como instalar PHPUnit
6. Un ejemplo de uso de PHPUnit
7. Como instalar XDebug
4. Conclusiones
5. Sobre el autor

1. Introducción

La vida da muchas vueltas y en estos días me he tenido que poner a hacer algunas cosillas en PHP. Como no tenía ni idea lo primero
que hice fue leerme el manual, y ya puedo afirmar «Ya sé PHP!». Bueno, en realidad sigo sin tener ni idea, pero por lo menos conozco
los principios del lenguaje 😉

Ante este panorama lo segundo que hice fue investigar como se puede hacer TDD en PHP. Para mi esto es fundamental, no
sólo porque considere que el TDD es imprescindible en si mismo, sino porque teniendo en cuenta mi inexperiencia con PHP, no me atrevo a tocar
ni una sola línea de código si no es con un buen test que me proteja de la caída.

Así, en este tutorial, voy a contaros como he configurado mi entorno (Mac OS X) para poder desarrollar en PHP con TDD y pruebas
automáticas con PHPUnit; un framework de pruebas unitarias del estilo xUnit,
donde incluso tenemos soporte para Stubs, Mocks, análisis
de cobertura, y muchas más cosas (de verdad muy recomendable si trabajamos con PHP).

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2.5 GHz Intel i7, 8GB 1333 Mhz DDR3, 256GB Solid State Drive).
  • AMD Radeon HD 6770M 1024 MB
  • Sistema Operativo: Mac OS X Lion 10.7.3
  • PHP 5.3.8
  • PEAR 1.9.4
  • PHPUnit 3.6.10

3. Como instalar PHP

Con Mac OS X ya tenemos instalado Apache (servidor Web) y PHP, sólo tenemos que activarlo.
Para ello editamos /etc/apache2/httpd.conf, buscamos la línea:

#LoadModule php5_module libexec/apache2/libphp5.so

Y le quitamos la #, es decir activamos el módulo de PHP del Apache.

Por defecto el directorio donde el Apache espera encontrar nuestras páginas es /Library/WebServer/Documents. Pero
esta ruta puede ser poco conveniente para albergar nuestros proyectos, así que en el mismo httpd.conf podemos crearnos
un Virtual Host, para ello añadimos algo como:

<Directory "/mis-proyectos/autentia/php/tutorial/php-unit">
    Options FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    Allow from all
</Directory>

<VirtualHost www.tutorial-phpunit.com>
    ServerName tutorial-phpunit.com
    DocumentRoot "/mis-proyectos/autentia/php/tutorial/php-unit"
</VirtualHost>

Donde /mis-proyectos/autentia/php/tutorial/php-unit es la ruta donde queremos tener los fuentes de nuestro proyecto PHP.

Nótese también que estamos usando el dominio www.tutorial-phpunit.com, este lo tendremos que haber definido en el
fichero /etc/hosts para que apunte a nuestra máquina:

127.0.0.1 www.tutorial-phpunit.com

También vamos a poner el fichero de configuración de PHP, el php.ini. Crear este
fichero de configuración va a ser muy sencillo porque nuevamente Mac OS X nos lo facilita dándonos uno por defecto,
así sólo tendremos que hacer:

$ sudo cp /etc/php.ini.default /etc/php.ini

Ahora reiniciamos el Apache con el comando:

$ sudo /usr/sbin/apachectl restart

(también podemos hacerlo desde System Preferences… -> Sharing -> Web Sharing)

4. Como instalar PEAR

PEAR, tal como lo definen en su propia página web, es un framework y un sistema de distribución para componentes PHP reutilizables. Básicamente podríamos decir que es un sistema de gestión de paquetes, al estilo de apt-get para los paquetes de Debian, o gem para las gemas de Ruby, o Maven para las librerías de Java.

En esta ocasión lo necesitamos para poder instalar luego PHPUnit.

De nuevo en Mac OS X su instalación es muy sencilla, basta con ejecutar:

$ cd /usr/lib/php ; sudo php install-pear-nozlib.phar

La salida del comando debe ser algo como:

[PEAR] Archive_Tar    - installed: 1.3.7
[PEAR] Console_Getopt - installed: 1.3.0
[PEAR] Structures_Graph- installed: 1.0.4
[PEAR] XML_Util       - installed: 1.2.1
[PEAR] PEAR           - installed: 1.9.4
Wrote PEAR system config file at: /private/etc/pear.conf
You may want to add: /usr/lib/php/pear to your php.ini include_path

Ahora tal como nos dice la última línea, vamos a modficiar el fichero/etc/php.ini, para tener en cuenta el
directorio donde se ha instalado PEAR. Para ello en dicho fichero buscamos la línea:

;include_path = ".:/php/includes"

Y la cambiamos por:

include_path = ".:/usr/lib/php/pear"

 

5. Como instalar PHPUnit

PHPUnit es el estándar de facto para hacer test unitarios en proyectos PHP.
Para instalar PHPUnit basta con hacer:

$ sudo pear config-set auto_discover 1
$ sudo pear install pear.phpunit.de/PHPUnit

La salida de este último comando será algo similar a:

Attempting to discover channel "pear.phpunit.de"...
downloading channel.xml ...
Starting to download channel.xml (804 bytes)
....done: 804 bytes
Auto-discovered channel "pear.phpunit.de", alias "phpunit", adding to registry
Attempting to discover channel "pear.symfony-project.com"...
downloading channel.xml ...
Starting to download channel.xml (865 bytes)
...done: 865 bytes
Auto-discovered channel "pear.symfony-project.com", alias "symfony", adding to registry
Did not download optional dependencies: phpunit/PHP_Invoker, use --alldeps to download automatically
phpunit/PHPUnit can optionally use package "phpunit/PHP_Invoker" (version >= 1.1.0)
phpunit/PHP_CodeCoverage can optionally use PHP extension "xdebug" (version >= 2.0.5)
downloading PHPUnit-3.6.10.tgz ...
Starting to download PHPUnit-3.6.10.tgz (118,595 bytes)
...done: 118,595 bytes
downloading File_Iterator-1.3.1.tgz ...
Starting to download File_Iterator-1.3.1.tgz (5,157 bytes)
...done: 5,157 bytes
downloading Text_Template-1.1.1.tgz ...
Starting to download Text_Template-1.1.1.tgz (3,622 bytes)
...done: 3,622 bytes
downloading PHP_CodeCoverage-1.1.2.tgz ...
Starting to download PHP_CodeCoverage-1.1.2.tgz (132,552 bytes)
...done: 132,552 bytes
downloading PHP_Timer-1.0.2.tgz ...
Starting to download PHP_Timer-1.0.2.tgz (3,686 bytes)
...done: 3,686 bytes
downloading PHPUnit_MockObject-1.1.1.tgz ...
Starting to download PHPUnit_MockObject-1.1.1.tgz (19,897 bytes)
...done: 19,897 bytes
downloading YAML-1.0.6.tgz ...
Starting to download YAML-1.0.6.tgz (10,010 bytes)
...done: 10,010 bytes
downloading PHP_TokenStream-1.1.3.tgz ...
Starting to download PHP_TokenStream-1.1.3.tgz (9,860 bytes)
...done: 9,860 bytes
install ok: channel://pear.phpunit.de/File_Iterator-1.3.1
install ok: channel://pear.phpunit.de/Text_Template-1.1.1
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.2
install ok: channel://pear.symfony-project.com/YAML-1.0.6
install ok: channel://pear.phpunit.de/PHP_TokenStream-1.1.3
install ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.1.2
install ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.1.1
install ok: channel://pear.phpunit.de/PHPUnit-3.6.10

Podemos instalar más módulos de PHPUnit en función de nuestras necesiadads (integración con base de datos, test de Selnium, …),
para ello podemos encontrar más información en
la página de instalación de PHPUnit.

6. Un ejemplo de uso de PHPUnit

Una buena forma de organizar nuestros test es separarlos del código de producción y tener un fichero de test por cada clase o fichero
php, duplicando la estructura de directorios de producción en el directorio de test, como si se tratara de un espejo. Por ejemplo,
la librería Object Freezer sigue al siguiente estructura:

Object                              Tests
|-- Freezer                         |-- Freezer
|   |-- HashGenerator               |   |-- HashGenerator
|   |   `-- NonRecursiveSHA1.php    |   |   `-- NonRecursiveSHA1Test.php
|   |-- HashGenerator.php           |   |
|   |-- IdGenerator                 |   |-- IdGenerator
|   |   `-- UUID.php                |   |   `-- UUIDTest.php
|   |-- IdGenerator.php             |   |
|   |-- LazyProxy.php               |   |
|   |-- Storage                     |   |-- Storage
|   |   `-- CouchDB.php             |   |   `-- CouchDB
|   |                               |   |       |-- WithLazyLoadTest.php
|   |                               |   |       `-- WithoutLazyLoadTest.php
|   |-- Storage.php                 |   |-- StorageTest.php
|   `-- Util.php                    |   `-- UtilTest.php
`-- Freezer.php                     `-- FreezerTest.php

Nosotros vamos a hacer un ejemplo más sencillo donde vamos a tener un directorio main con el código de producción,
y un directorio test con el código de los test. De esta forma tendremos los ficheros:

<?php
/** /mis-proyectos/autentia/php/tutorial/php-unit/AdictosTutorial.php */

class AdictosTutorial {

    public function greet() {
        return 'Hola Adictos Al Trabajo !!!';
    }
}

?>
<?php
/** /mis-proyectos/autentia/php/tutorial/php-unit/test/AdictosTutorialTest.php */

require_once 'main/AdictosTutorial.php';

class AdictosTutorialTest extends PHPUnit_Framework_TestCase {

    public function testReturnGreeting() {
        $adictos = new AdictosTutorial();
        $this->assertEquals('Hola Adictos Al Trabajo !!!', $adictos->greet());
    }
}

?>

Desde el directorio /mis-proyectos/autentia/php/tutorial/php-unit ejecutaremos el siguiente comando
para lanzar los test:

$ phpunit test

Y obtendremos la siguiente salida con los resultados de la ejecución de los test (cada . representa un test):

PHPUnit 3.6.10 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 5.50Mb

OK (1 test, 1 assertion)

Esto es sólo la punta del iceberg, así que os recomiendo que leáis la completísima documentación de PHPUnit.

7. Como instalar XDebug

XDebug es una herramienta de depuración y análisis para PHP. En principio la parte de
depuración no nos interesa porque nosotros preferimos el camino del TDD 😉 pero si nos puede venir muy bien para hacer análisis de
rendimiento o para ver la cobertura de nuestros test de PHPUnit.

Para activarlo editamos el fichero /etc/php.ini y buscamos la línea:

;zend_extension="/usr/lib/php/extensions/no-debug-non-ztsV-20090626/xdebug.so"

Le quitamos el ; para descomentarla y ya estamos listos!

Si vamos a querer hacer análisis de cobertura necesitamos definir nuestra zona horaria, para ello buscamos la línea:

;date.timezone =

Y pondremos los datos de nuestra zona horaria, por ejemplo para Madrid:

; Madrid, Spain, Europe
date.timezone = "Europe/Madrid"
date.default_latitude = 40.416126
date.default_longitude = -3.696706

Ahora para lanzar los test y medir la cobertura podemos ejecutar:

$ phpunit --coverage-html ./report test

Donde ./report es el directorio donde dejaremos los resultados del análisis de cobertura en formato HTML,
y test es el directorio donde tenemos los tests.

4. Conclusiones

PHP! Quién dijo miedo?!?!?! Haciendo TDD y teniendo una buena batería de test, no hay lenguaje que se nos resista!

5. Sobre el autor

Alejandro Pérez García, Ingeniero en Informática (especialidad de
Ingeniería del Software) y Certified ScrumMaster

Socio fundador de Autentia (Desarrollo de software, Consultoría,
Formación)

mailto:alejandropg@autentia.com

Autentia Real Business Solutions S.L. – «Soporte a Desarrollo»

http://www.autentia.com

 

Alejandro es socio fundador de Autentia y nuestro experto en Java EE, Linux y optimización de aplicaciones empresariales. Ingeniero en Informática y Certified ScrumMaster. Seguir @alejandropgarci Si te gusta lo que ves, puedes contratarle para darte ayuda con soporte experto, impartir cursos presenciales en tu empresa o para que realicemos tus proyectos como factoría (Madrid). Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad