Cómo testar nuestras aplicaciones PHP con PHPUnit
¡Hola! En este tutorial vamos a volver a PHP y esta vez nos toca ver como crear tests unitarios. Esto nos ayudará a crear aplicaciones más robustas y menos propensas a fallos 💪.
Pero antes de nada y para el que no lo tenga claro...
¿Qué son los test unitarios (unit test)?
Básicamente son scripts que creamos para testar bloques de código en concreto. El test recuperará los datos de ese bloque de código y lo validará gracias a las funciones que nos provee la librería que utilizaremos. De esta forma nos aseguramos que todo está en perfectas condiciones cuando realizamos un cambio en nuestra aplicación antes de subirla a producción y nos ahorraremos posibles dolores de cabeza.
Ahora que ya lo tenemos claro, vamos a crear un proyecto para verlo todo más claro. Para ello, primero debemos tener claro como utilizar composer en nuestros proyectos. Si no lo tienes muy claro, te dejo este tutorial en el que explico todo lo que necesitas saber sobre composer.
Una vez aclarado el tema composer, creamos estructura de nuestro proyecto. Primero, crearemos dos carpetas en el directorio raíz, una llamada app y otra llamada tests. Después, crearemos el archivo composer.json con el siguiente contenido:
{
"name": "alber/unit-test-php",
"description": "Tutorial de configuraci\u0000n de un proyecto con PHPUnit",
"type": "project",
"license": "MIT",
"authors": [
{
"name": "Alberto",
"email": "alberto.r.caballero.87@gmail.com"
}
],
"minimum-stability": "stable",
"require": {
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
}
Una vez hecho esto, lanzamos el comando composer dump para que genere el autoload:
composer dump
Ahora vamos a instalar PHPUnit. Esta será la librería que utilizaremos para crear nuestros tests.
composer require --dev phpunit/phpunit
Una vez hecho esto, necesitaremos crear un archivo de configuración para PHPUnit. Para ello, vamos al directorio raíz de nuestro proyecto y creamos un archivo llamado phpunit.xml que contendrá el siguiente código:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuite name="Test directory">
<directory>tests</directory>
</testsuite>
</phpunit>
Básicamente lo que hacemos es pasarle en el atributo bootstrap el archivo de carga de clases y dentro de testsuite, el directorio donde guardaremos los tests que en nuestro caso será en la carpeta tests.
Ahora, para este ejemplo, vamos a crear una clase que nos servirá de conejillo de indias para hacer nuestras pruebas. Para ello, vamos al directorio app y dentro de él, creamos una carpeta llamada Classes. Una vez creada esta carpeta, accedemos a ella y dentro creamos un archivo llamado Calc.php que contendrá el siguiente código:
<?php
namespace App\Classes;
class Calc
{
public function sum(int $num1, int $num2)
{
return $num1 + $num2;
}
}
Como veis, es un código muy sencillo. Simplemente tiene una función que recibe dos números y realiza una suma.
Una vez hecho esto, es hora de crear nuestro primer test. Para ello, vamos a la carpeta tests y en ella, crearemos un archivo llamado CalcTest.php. Es muy importante que el nombre del archivo tenga formato CamelCase y termine con Test.php. Esta es la forma que utiliza PHPUnit para diferenciar cuando es un test y cuando no. Si no tiene este formato, este test no se ejecutará así que no olvidéis este detalle.
Una vez creado el archivo, lo abrimos y añadimos el siguiente código:
<?php
use PHPUnit\Framework\TestCase;
use App\Classes\Calc;
class CalcTest extends TestCase
{
public function test_sum()
{
$calc = new Calc();
$result = $calc->sum(1, 2);
$this->assertEquals(3, $result);
}
}
Como podréis observar, lo primero que hacemos es añadir la librería de PHPUnit y nuestra clase Calc.
El siguiente paso es crear nuestra clase que deberá llamarse igual que nuestro archivo y que extenderá de la clase TestCase. De esta forma podremos utilizar las funcionalidades de PHPUnit para crear nuestros tests.
Dentro de la clase crearemos nuestros tests. En este caso, solo tenemos uno llamado test_sum. Todos los métodos que queramos que se ejecuten deben empezar por el nombre test_ y deben tener un formato de nombre snake_case, si no es así, PHPUnit los ignorará y no se ejecutarán. Además, cada test debe ser autoconclusivo y no depender de otros tests para su correcto funcionamiento.
Dentro de test_sum lo que hacemos es crear una instancia de la clase Calc y ejecutar el método sum el cual retornará un resultado. Para realizar la validación del test usaremos el método assertEquals el cual es un método de la clase TestCase que significaría algo así como afirma si son iguales. En este método, como primer parámetro pasamos el resultado que esperamos obtener y en el segundo, el resultado que hemos obtenido para confirmar que todo esté 👌.
Ahora que ya tenemos nuestro test creado es hora de probarlo. Para ello, vamos a nuestro directorio raíz y lanzamos el siguiente comando:
php vendor/phpunit/phpunit/phpunit
Si todo ha ido bien, deberíamos recibir un mensaje afirmando que todos nuestros tests han pasado de forma exitosa.
Aparte de assertEquals, tenemos muchos más tipos de afirmaciones como podéis ver en este listado https://phpunit.readthedocs.io/es/latest/assertions.html, Por ejemplo, si queremos confirmar que el resultado que retorna es un entero, podemos usar AssertIsInt:
<?php
use PHPUnit\Framework\TestCase;
use App\Classes\Calc;
class CalcTest extends TestCase
{
public function test_sum()
{
$calc = new Calc();
$result = $calc->sum(1, 2);
$this->assertEquals(3, $result);
$this->assertIsInt($result);
}
}
setUp()
y tearDown()
En ocasiones puede pasar que en nuestros distintos test se repitan códigos tanto al inicio como al final, lo que hará que tengamos mucho código repetido. Para solucionar esto tenemos los métodos setUp y tearDown. El método setUp se lanzará siempre antes de la ejecución de cada test y el método tearDown se lanzará justo cada vez que termine uno de nuestros tests.
Para verlos en funcionamiento, volvemos a la clase Calc y añadimos un nuevo método de tal forma que ahora quedará así:
<?php
namespace App\Classes;
class Calc
{
public function sum(int $num1, int $num2)
{
return $num1 + $num2;
}
public function res(int $num1, int $num2)
{
return $num1 - $num2;
}
}
Una vez hecho esto, volvemos a nuestro test y lo modificamos para añadir un nuevo test y también para ver como aplicar el método setUp():
<?php
use PHPUnit\Framework\TestCase;
use App\Classes\Calc;
class CalcTest extends TestCase
{
public $calc = null;
public function setUp(): void
{
$this->calc = new Calc();
}
public function test_sum()
{
$result = $this->calc->sum(1, 2);
$this->assertEquals(3, $result);
$this->assertIsInt($result);
}
public function test_res()
{
$result = $this->calc->res(2, 1);
$this->assertEquals(1, $result);
$this->assertIsInt($result);
}
}
Como veis hemos añadido el método setUp que se encargará de crear la instancia de la clase cada vez que se ejecute un test. De esta forma nuestros test se verán más limpitos y claros.
Conclusiones
La idea de los tests es que siempre los ejecutemos antes de una subida a producción. De esta forma validaremos los cambios en nuestros proyectos y será más fácil proteger nuestro código frente a fallos, así que os recomiendo que siempre que podáis los utilicéis. Vuestro corazón os lo agradecerá cuando subáis cambios delicados a producción 😂.
Cualquier duda la podéis dejar en la caja de comentarios. Como siempre os dejo el enlace al proyecto.
Espero que este post te ayude y como siempre, te recomiendo seguirme en Twitter para estar al tanto de los nuevo contenido. Ahora también puedes seguirme en Instagram donde estoy subiendo tips, tutoriales en vídeo e información sobre herramientas para developers.
Por último os dejo mi guía para aprender a trabajar con APIs donde explico todo el funcionamiento de una API, el protocolo HTTP y veremos como construir una API con arquitectura REST.
Nos leemos 👋.