Ya hemos visto como crear test con PHPUnit, también hemos visto técnicas sobre como mejorar nuestros tests. Llegados a este punto tenemos claro que es necesario hacer test unitarios, pero ¿que pasa cuando queremos ejecutar muchos tests unitarios? PHPUnit ejecuta test secuencialmente, pero esto a veces puede ser una tarea lenta.
Existen muchas formas de lanzar test de PHPUnit en paralelo y en este post veremos algunas herramientas para que los tests unitarios que tenemos puedan ejecutarse a la vez.
Creando el proyecto
Para poder probar las distintas soluciones vamos a crear un pequeño proyecto de ejemplo con una serie de test y algunos retardos para poder medir cuánto se gana ejecutando en paralelo varios tests unitarios.
Así que lo primero será crear un nuevo proyecto con composer, donde añadimos PHPUnit como dependencia, ejecutamos composer install
y creamos un archivo llamado phpunit.xml.dist en la raíz del proyecto.
Este archivo contendrá la configuración de PHPUnit:
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "vendor/autoload.php" >
<testsuites>
<testsuite name="Tutorial Test Suite">
<directory>tests/</directory>
</testsuite>
</testsuites>
</phpunit>
Para las pruebas vamos a utilizar una serie de tests simples a los que les añadiremos un pequeño sleep para así poder medir algunos tiempos. Este será nuestro test para las pruebas:
public function testNothing()
{
sleep(1);
$this->assertTrue(true);
}
Vamos a crear 5 archivos llamados 01Test, 02Test,… y dentro de cada archivo 5 test como el anterior testNothing01, testNothing02,… una vez lo tengamos todo, ejecutamos y más o menos obtendremos un timepo como este:
Time: 56.07 seconds, Memory: 4.50Mb
OK (50 tests, 50 assertions)
Ahora veremos como ir utilizando distintas herramientas para lanzar test de PHPUnit en paralelo.
Ejecutando test con un script
Una de las primeras cosas que se nos pueden ocurrir para ejecutar test PHPUnit en paralelo es crear un script para lanzar varios procesos test a la vez. No es la mejor manera pero podemos utilizar un script descrito en: http://jwage.com/post/30490205475/a-cool-script-for-running-phpunit-tests-in-parallel
Este script es capaz de ejecutar varios hilos a la vez y con ello ejecutar varios tests.
Parallel-phpunit
Una de las herramientas disponibles para poder ejecutar test de PHPUnit en paralelo es parallel-phpunit si no queremos utilizar composer esta es una de las que más me gusta.
Instalando paralel-phpunit
Para instalarla solo tenemos que clonarnos el repositorio de github donde queramos y hacer un enlace de la carpeta bin/ a /usr/bin/.
Listo con esto ya podemos utilizar el comando parallel-php en vez de phpunit. Esto no será útil sobre todo en entornos de integración continua como Jenkins, así haremos que nuestros tests vayan más rápido.
Cómo se utiliza parallel-phpunit
Básicamente el comando es parallel-phpunit y se utiliza
parallel-phpunit [phpunit y/p parallel-phpunit argumentos] <directorio de los test>
por ejemplo así:
parallel-phpunit /var/www/miproyecto/tests/
Algunos argumentos pueden ser:
- —pu-verbose: más información
- —pu-thread: número máximo de hilos, por defecto 3
Cómo funciona
parallel-phpunit busca todos los test que en la carpeta y subcarpetas especificadas, es decir todos los ficheros que terminan con .Test.php
A tener en cuenta
Según comentan en la documentación puede que reportes como los de cobertura de código, etc, no terminen del funcionar del todo bien.
Bueno, después de esta pequeña introducción, ¿cuanto tardamos ahora en ejecutar nuestros tests? Utilizando el comando time vamos a realizar una pequeña comparativa utilizando 5 hilos
real 0m10.944s
user 0m2.723s
sys 0m2.250s
Viendo los tiempos hemos mejorado bastante al lanzar los tests de PHPUnit en paralelo.
paratest
Otra utilidad para poder lanzar test de PHPUnit en paralelo es paratest. Esta utilidad creada por brianium es una de las recomendadas por phpunit como plugins “oficiales” (http://phpunit.de/plugins.html). Es muy útil si utilizamos composer, ya que para instalar paratest solo tenemos que añadir la dependencia a composer
"require": {
"brianium/paratest": "dev-master"
}
Después de instalarla o actualizar nuestras dependencias con composer update tendremos en la carpeta vendor/bin/paratest
el ejecutable para lanzarla 🙂
Para ejecutar los tests en paralelo con paratest solo tenemos que abrir la consola, ir al proyecto y ejecutar vendor/bin/paratest
. Por defecto leerá nuestra configuración de phpunit.xml.dist y ejecutará los test
Si ejecutamos la tarea paratest por defecto (5 hilos) y leyendo el archivo de ocnfiguaracion visto arriba obtenemos este resultado
Time: 12.64 seconds, Memory: 4.25Mb
OK (50 tests, 50 assertions)
real 0m12.772s
user 0m10.153s
sys 0m1.052s
Parece que es un poco más lento, aunque tenemos la ventaja de que es mucho más configurable a través del XML, además tiene como ventaja que solo es necesario tener que añadirlo como dependencia en composer para que empiece a funcionar.
Conclusiones
Existen muchas formas de lanzar test en paralelo, desde un simplescript hasta soluciones recomendadas por PHPUnit para lanzar test en paralelo como es paratest. La idea clave que quiero hacer notar es que es necesario hacer test, al menos unitarios y que la excusa de que son lentos no es válida si conocemos las herramientas necesarias para hacerlo un poco más rápido.