Introducción a las pruebas unitarias en PHP



Este es el inicio de una serie de artículos en donde aprenderás de forma clara y con ejemplos prácticos, como programar en PHP usando pruebas unitarias (unit testing). Al final del artículo te dejaré el código fuente para que puedas descargarlo.

Contenido del artículo:

Preparar el ambiente para pruebas unitarias en PHP

Para seguir estos ejemplos primero debes crear una carpeta e iniciar un proyecto con Composer. Entonces crear una carpeta y ejecuta este comando y sigues todos los pasos del asistente.

composer init

Ahora necesitamos agregar la librería PHPUNIT, corriendo este comando:

composer require phpunit/phpunit --dev

Mi archivo composer.json ahora luce como este:

{
    "name": "codigonaranja/unittest",    
    "authors": [
        {
            "name": "luis cruz",
            "email": "[email protected]"
        }
    ],
    "autoload": {
		"psr-4": {
			"App\\": "src/"
		}
    },
    "require-dev": {
        "phpunit/phpunit": "^9.5"
    } 
}

Con esto es suficiente para comenzar a crear las pruebas o unit testing. Lo más recomendable al programar es iniciar, escribiendo el código de las pruebas y luego escribir el código del programa, de esta forma sabremos que pruebas debe pasar nuestro código y podremos saber si está libre de errores.

Las listas pueden estar separadas por comas

Esta es nuestra primera prueba, hemos definido que cuando alguien ingresa una lista, cada valor puede ir separado por una coma. Entonces escribimos nuestra primera prueba.

Creemos una carpeta llamada Tests y dentro un archivo llamado ListParserTest.php, este puede ser el contenido del archivo:

<?php
namespace Tests;
use App\ListParser;
use PHPUnit\Framework\TestCase;

class ListParserTest extends TestCase
{
    public function test_funciona_con_listas_separadas_por_coma(){

        $parser = new ListParser();
     
        $lista_array = ["vba","c#","php"];
        $lista_test = $parser->parse("vba,c#,php");

         

        $this->assertSame($lista_test,$lista_array);
         
    }
}

Hay unas cosas que debes de considerar para que tu prueba se ejecute correctamente:

  1. Debes crear una clase que extienda a la clase TestCase
  2. Cada prueba se hace creando una función la cual debe iniciar con el nombre test_ (hay una forma de evitarlo, pero por el momento lo vamos a hacer así). Esto es solo una recomendación, pero el nombre del test debería reflejar el objetivo de la prueba, en este caso indica que es válido que una lista esté separada por comas.
  3. Finalmente, debemos ejecutar la prueba, en este caso use assertSame para verificar que el resultado de nuestro programa regrese el valor que espero.

Ahora solo debemos escribir el código que pueda pasar la prueba. Entonces creamos una carpeta llamada src con un archivo llamado ListParser.php

<?php

namespace App;

class ListParser{
    public function parse(string $list): array
    {
        return explode("," , $list);
    }
}

Como vemos este código es muy sencillo, solo recibe una lista y usa la función explode de PHP para dividir el texto usando una coma, como delimitador. Para correr las pruebas unitarias podemos usar este comando:

vendor\bin\phpunit tests --colors

Nota: Yo estoy usando Windows, si usas Linux es posible que debas cambiar son símbolos \ por /

Y veremos una salida como esta:

Ejecución de pruebas unitarias con PHP

Aparentemente, nuestro código ya funciona, pero antes debemos hacer más pruebas para saber si está preparada para el mundo real.

Las listas pueden estar separadas por comas y después de la coma puede ir un espacio.

Ahora vamos a crear otra prueba para ver si nuestro programa funciona, aun cuando después de una coma, hay un espacio en blanco. El código de la prueba es muy similar, pero ahora cambia el dato que enviamos en la prueba. Vamos a agregar una función más en nuestras pruebas:

public function test_funciona_con_listas_separadas_por_coma_y_espacio(){

        $parser = new ListParser();
     
        $lista_array = ["vba","c#","php"];
        $lista_test = $parser->parse("vba, c#,php");         

        $this->assertSame($lista_test,$lista_array);
         
    }

Como podemos ver es el mismo código, pero en la prueba hemos agregado un espacio en blanco antes del valor c#. Veamos primero el resultado de las pruebas.

Prueba unitaria fallida

Como podemos ver, la prueba ha fallado, entonces debemos corregir la función. Una forma fácil de corregirlo seria usando la función array_map de PHP para aplicar un trim a cada valor y eliminando el espacio en blanco, de esta forma nuestra función quedaría así:

<?php

namespace App;

class ListParser{
    public function parse(string $list): array
    {
        return array_map(fn ($a) => trim($a), explode("," , $list));
    }
}

Si ejecutamos las pruebas unitarias veremos que ahora pasa ambas pruebas. Pero ahora, si alguien propone que las listas pueden estar separadas por una coma o un espacio en blanco, nuestro código no estaría preparado.

Las listas pueden estar separadas por una coma y/o un espacio en blanco.

Lo primero que necesitamos es agregar una prueba más a nuestro set de pruebas, esto lo podemos hacer con una función como esta:

public function test_funciona_con_listas_separadas_por_coma_y_o_espacio(){

        $parser = new ListParser();
     
        $lista_array = ["vba","c#","php"];
        $lista_test = $parser->parse("vba c#,php");         

        $this->assertSame($lista_test,$lista_array);
         
    }

Ahora tenemos que corregir nuestro programa para que pueda pasar este escenario y vemos que la función explode ya no es suficiente. Tenemos que hacer un cambio total, esto podría suponer un gran problema porque no sabemos qué errores podría causar cambiar el código en su totalidad, pero gracias a las pruebas unitarias que hemos escrito sabremos si sigue funcionando para todos los casos que escribimos.

Para pasar las pruebas ahora vamos a usar la función preg_split de PHP, esta función divide un string en elementos de un arreglo, pero es mucho más potente que explode porque usa expresiones regulares. Si no estás familiarizado con las expresiones regulares, aquí hay un artículo muy breve y completo sobre el tema.

En el nuevo código se indica que los separadores de lista son una coma o un espacio en blanco, y que antes de estos separadores puede ir o no un espacio en blanco.

<?php

namespace App;

class ListParser{
    public function parse(string $list): array
    {
        return preg_split("| ?[, ] ?|", $list);
    }
}

Como puedes ver tuvimos que cambiar la función en su totalidad, pero gracias a las pruebas unitarias podemos tener confianza de que hace bien su trabajo en todos los casos previstos.

Mejorar un poco las pruebas unitarias

Vamos a mejorar un poco nuestro código para las pruebas unitarias. Al programar es bueno reducir el código al mínimo posible, y vemos que en cada prueba tenemos que crear una instancia de la clase que estamos probando. Podemos crear una función llamada setUp que se encargue de preparar o realizar algunas configuraciones previas a las pruebas, en nuestro caso la usaremos para crear una instancia de la clase que estamos probando.

En la clase en donde creamos las pruebas unitarias vamos a agregar una variable y un método:

 protected ListParser $listParser;
 protected function SetUp(): void
 {
    $this->listParser = new ListParser();
 }

Y ahora cambiamos las pruebas unitarias para que queden de esta forma:

public function test_funciona_con_listas_separadas_por_coma(){
   $lista_array = ["vba","c#","php"];
   $lista_test = $this->listParser->parse("vba,c#,php");
   $this->assertSame($lista_test,$lista_array);
}

Aquí está el código completo de las pruebas unitarias:

<?php
namespace Tests;
use App\ListParser;
use PHPUnit\Framework\TestCase;

class ListParserTest extends TestCase
{

    protected ListParser $listParser;
    protected function setUp(): void
    {
        $this->listParser = new ListParser();
    }


    public function test_funciona_con_listas_separadas_por_coma(){

        $lista_array = ["vba","c#","php"];
        $lista_test = $this->listParser->parse("vba,c#,php");         

        $this->assertSame($lista_test,$lista_array);
         
    }

    public function test_funciona_con_listas_separadas_por_coma_y_espacio(){

        $lista_array = ["vba","c#","php"];
        $lista_test = $this->listParser->parse("vba, c#,php");         

        $this->assertSame($lista_test,$lista_array);
         
    }

    public function test_funciona_con_listas_separadas_por_coma_y_o_espacio(){

        $lista_array = ["vba","c#","php"];
        $lista_test = $this->listParser->parse("vba c#,php");         

        $this->assertSame($lista_test,$lista_array);
         
    }
}

Conclusiones

Podríamos hacer más pruebas como, por ejemplo, que pasaría si la lista está vacía o si solo tiene un elemento. Entre más pruebas hagamos, menos problemas tendremos cuando nuestros programas estén publicados para su uso.

Puedes descargar el código final en este enlace.

Si tienes alguna duda o comentario, por favor escribe un comentario en este artículo o si puedes dime que piensas sobre las pruebas unitarias.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *