Agregar PHPUnit a tu proyecto PHP con composer


Con el tiempo, los proyectos y librerías tienden a evolucionar ya sea para agregar nuevas funcionalidades o simplemente para mejorar el rendimiento y desempeño. Una manera de garantizar que nuestra librería se mantendrá estable a lo largo de éstas mutaciones es a través de una serie de pruebas.

Una prueba es un fragmento de código que se asegura de que una función o clase haga exactamente lo que se le designó.

PHP Unit es un framework que nos permite crear y ejecutar pruebas para nuestro código de una manera muy sencilla, además de brindarnos herramientas para revisar que tanto porcentaje de nuestro código ha sido probado (coverage) y la complejidad de nuestro código (complexity).

Para ésta guía utilizaremos el código creado en el blog "Inicializa un proyecto PHP usando composer" para establecer los primeros pasos, si deseas leerlo puedes ingresar aquí, de lo contrario, te dejo el repositorio en github, el cual puedes clonar o descargar como zip.

La estructura inicial de nuestro proyecto debería verse de la siguiente manera:

Primero que nada debemos instalar PHPUnit, teniendo composer esto se facilita bastante, solo debemos ejecutar el siguiente comando:

Se utiliza la bandera --dev para indicarle a composer que la libreŕia solo e utilizará en entornos de desarrollo.

Una vez ejecutado éste comando, composer se encargará de realizar la instalación de todos los elementos necesarios. Estos elementos se encontrarán situados en la carpeta vendor .

Si estás utilizando algún sistema de control de versiones, es importante que agregues la carpeta vendor a los archivos ignorados, ya que con composer se pueden volver a instalar fácilmente.

Si queremos asegurarnos de que phpunit se ha instalado correctamente, podemos revisar el archivo composer.json el cual debería tener una nueva entrada llamada require-dev con algo similar a lo siguiente:

En esta ocasion, composer instaló la versión 8.5 de phpunit, ésto puede variar dependiendo de la fecha en la que se lleve a cabo ésta guia.

Registrar carpeta de pruebas en composer

Para organizar nuestro proyecto crearemos la carpeta pruebas en ella colocaremos de manera ordenada todas las pruebas que se irán creando a lo largo del desarrollo, ésta carpeta estará registrada en composer para poder utilizar los nombres de espacio de nuestro proyecto sin complicaciones.

Para ello, creamos la carpeta en la raíz de nuestro proyecto, quedando una estructura similar a la siguiente:

Ahora, registramos la carpeta pruabas con el namespace Javleds\Pruebas, para ello, editaremos el archivo composer.json, y agregaremos la entrada autoload-dev.psr-4, de la siguiente manera:

Nota: En el ejemplo utilizamos el namespace Javleds\FabulosaLibreria, pero tu deberias utilizar un nombre de espacio único para tu proyecto compuesto de USUARIO_GIT\NOMBRE_LIBRERIA.

A diferencia de la entrada autoload, las clases y archivos registrados en la entrada autoload-dev solo estarán disponibles para entornos de desarrollo.

Es tiempo de revisar si phpunit funciona correctamente, para ello, crearemos una prueba para la funciónelementoAleatorio que se encuentra en el archivo funciones_globales.php, esta función luce así:

La función recibe un arreglo con elementos de cualquier tipo y regresa un elemento de manera aleatoria, nuestra prueba se encargará de asegurarse que la función elementoAleatorio nos regresa siempre algún valor, y cuyo valor debe estar contenido en ese arreglo. Crearemos el archivo pruebas/FuncionesGlobalesTest.php con lo siguiente:

Las pruebas deben extender de la clase PHPUnit\Framework\TestCase, en ésta clase se encuentran todas las utilidades que nos brinda PHPUnit para crear pruebas.

La prueba que creamos inicializa un arreglo con los valores del 1 al 5, posteriormente manda a llamar la función elementoAleatorio y revisa que:

  1. El valor regresado no sea nulo
  2. Que el valor regresado por la función exista dentro del arreglo inicial.

Ahora, llamaremos le indicaremos a PHPUnit que queremos ejecutar esa prueba con el comando:

Este comando buscará dentro de la carpeta pruebas todos los archivos que terminen con la palabra Test.php y ejecutará las funciones que comienzan con el sufijo test o tengan la anotación @test.

Si todo sale bien, podremos ver un resultado similar al siguiente:

Esto quiere decir que se ejecutó 1 prueba, de las cuales 1 cumple con lo establecido, en ella se realizaron 2 aserciones (la del valor nulo y la del valor existe en el arreglo).

Creando un archivo de configuración de PHPUnit

Ahora bien, ya sabiendo que podemos ejecutar pruebas, lo ideal sería configurar PHPUnit para no tener que especificar las rutas de nuestras pruebas en cada ocasión, además de otra serie de configuraciones. Para ello crearemos el archivo phpunit.xml en la raíz del proyecto con lo siguiente:

El directorio debería quedar de la siguiente manera:

En el archivo podemos encontrar las configuraciones necesarias para nuestro proyecto, pero en cuanto se requieran más configuraciones, puedes irlas agregando acorde a la documentación oficial, más información aquí

En cuyo documento tenemos:

  • phpunit.bootrstrap: Le indicamos a PHPUnit que debe cargar el archivo vendor/autoload.php antes de comenzar a ejecutar las pruebas, por si no estás muy familiarizado con composer, el archivo vendor/autoload.php contiene el registro de todas clases y funciones de las que depende nuestro proyecto, incluyendo las que registramos manualmente en las seccion autoload del archivo compoaser.json, este archivo se crea automáticamente por composer cada que instalamos una nueva dependencia y/o cuando ejecutamos el comando composer dump-autoload.
  • phpunit.colors: Le indicamos a PHPUnit que al terminar nos indique con colores rojo y verde el resultado de nuestras pruebas. Rojo cuando hay errores o verde cuando todo se ejecutó correctamente.
  • phpunit.convertErrorsToExceptions: Le indicamos a PHPUnit que convierta cualquier error en una excepción.
  • phpunit.convertNoticesToExceptions: Le indicamos a PHPUnit que convierta cualquier evento de información en una excepción.
  • phpunit.convertWarningsToExceptions: Le indicamos a PHPUnit que convierta cualquier alerta de PHP en una excepción.
  • testsuites.testsuite: Le indicamos a PHPUnit cual es el directorio que contiene nuestras pruebas, en este apartado se pueden crear grupos de pruebas dependiendo de su función, pero en éste ejemplo solo tenemos una para todo el proyecto.
  • filter.whitelist: Esta configuración le indica a PHPUnit que los archivos contenidos en el directorio src deberán ser contemplados para calcular la cobertura de pruebas.

Ahora bien, para ejecutar nuestra suite de pruebas solamente debemos ejecutar el comando:

De manera automática, este comando leerá el archivo phpunit.xml y ejecutara las suites declaradas allí, ya no será necesario indicarle nada más.

Cobertura de código

Otra ventaja de tener definidas suites de pruebas en el arcivo phpunit.xml es que podemos generar un reporte con la Cobertura de pruebas que tiene nuestro código, PHPUnit nos brinda diversos formatos para éste reporte, yo te recomiendo el formato HTML, quien te genera una página web con los resultados.

Para generar este reporte solo debemos agregar la bandera --coverage-html con el nombre del directorio en el que se guardarán los archivos, ejemplo:

Este comando ejecutara todas las pruebas del archivo phpunit.xml y a demás nos creará la carpeta coverage con algunos archivos, nosotros abriremos con nuestro navegador de preferencia el archivo coverage/index.html y debe mostrarnos de manera interactiva que archivos ya tienen pruebas y qué porcentaje de ese código ha sido probado. Si seguiste el tutorial con el código del blog "Inicializa un proyecto PHP usando composer", entonces, deberías poder ver algo similar a lo siguiente:

coverage

En dónde el reporte nos indica que el archivo src/funciones_globales.php tiene un 100% de cobertura, sin embargo, no tenemos pruebas definidas para src/Mensajes.php y src/Utilerias/Calculadora.

Conclusión y tips

Agregar o no pruebas siempre ha sido un tema de controversia, en mi experiencia, las pruebas son necesarias si quieres que tu proyecto sea escalable y este pensado para ser un proyecto colaborativo. Las pruebas permiten que tu código crezca y a demás se puede refactorizar con el tiempo sin temor a dañar las partes de código que ya funcionan, además de que te permiten integrar herramientas de integración y despliegue continuo.

Tips:

  • Antes de comenzar a escribir código, se recomienda diseñar una prueba primero, posterior a la prueba, comenzar a desarrollar la funcionalidad que esperas siempre se apegará al propósito original. Realizar la prueba y posteriormente el código es una buena práctica y una metodología conocida como TDD (Test Driven Design).

  • No te preocupes por tener el 100% de cobertura de tu código, enfócate en probar aquellas cosas que requieran procesamiento de la computadora, por ejemplo, operaciones matemáticas complejas, creaciones de archivos, inserciones y ediciones de la base de datos, entre otros. Un 80% de cobertura es muy aceptable.

  • Piensa tus pruebas orientadas a casos de uso o a tus reglas de negocio.

  • Elabora pruebas sencillas de leer, ninguna prueba debe ser más compleja que el código que se está probando.

  • Si tu proyecto consume API's de terceros, procura que ninguna de tus pruebas utilice estos servicios, hay técnicas para "simular" una llamada a una API, estas se conocen como mocks o stubs, puedes revisar un poco más aquí.

  • Dentro de tu carpeta de pruebas/ intenta ordenar el código de tal manera que sea un espejo de la carpeta src/, esto facilitará el mantenimiento de las pruebas y mantendrá el código organizado, un ejemplo para el proyecto actual sería:

    fabulosa_libreria/
    |--- src/
    |--- funciones_globales.php
    |--- Mensajes.php
    |--- Utilerias/
    |--- Calculadora.php
    |--- pruebas/
    |--- FuncionesGlobalesTest.php
    |--- MensajesTest.php
    |--- Utilerias/
    |--- CalculadoraTest.php

¡Gracias por tu tiempo!, esta guia es un poco larga, pero espero que te sirva mucho en tu día a día, te invito a que agregues pruebas a tus proyectos y si ya has trabajado con PHPUnit te invito a que nos cuentes tu experiencia en los comentarios.

¡Hasta la próxima!