IronWoods.es

Desarrollo web

Blog / Laravel / Testing en Laravel

Por defecto, en Laravel se "plantean" dos tipos de test: pruebas de características (feature tests) y pruebas unitarias (unit tests).

Entonces, en una instalación limpia de Laravel (Laravel 7), encontramos el directorio "tests" que contiene:

  • El directorio "Feature".
  • El directorio "Unit".
  • Y los ficheros "CreatesApplication.php" y "TestCase.php", que en principio no debemos tocar.

Cada uno de los directorios contiene una clase de prueba de ejemplo. Además, en el directorio raíz de la Laravel hay un fichero de configuración de PHPUnit: "phpunit.xml".

Organización de pruebas

Contamos con los directorios "Feature" y "Unit", queda algunas preguntas pendientes:

  • 1. ¿Dónde colocamos cada una de nuestras clases de prueba?
  • 2. ¿Qué debemos probar?
  • 3. ¿Cómo debemos probarlo?
¿Dónde colocamos cada una de nuestras clases de prueba?

Para responder a la primera pregunta debemos poder diferenciar ¿qué tipo de pruebas contiene cada una de nuestras clases? y saber ¿cómo va a ejecutar Laravel las pruebas?

Primero lo fácil, Laravel ejecuta las pruebas en este orden: primero las pruebas dentro del directorio "Unit", seguidamente las pruebas dentro del directorio "Feature". Esto es por dos motivos, se espera que las primeras sean rápidas y las segundas, no tanto. Además, partes que conforman las "pruebas de características" deberán pasar previamente "pruebas unitarias".

Dentro de cada uno de los directorios principales, la ejecución sigue un orden alfabético con las clases de prueba, y dentro de éstas, se ejecutan las pruebas de arriba a abajo.

Dicho esto, en general en Feature pondremos pruebas sobre "características completas del sistema", lo que incluye una petición Http, que implica una ruta, un controlador, probablemente llamadas a la BD, middlewares, etc. Incluyen bastante pasos y cierta complejidad... Por eso dije que dependen a su vez de partes más pequeñas que deben pasar previamente, al menos en parte, pruebas unitarias.

La prueba unitaria se usa con funcionalidades concretas, entonces en Unit se pondrán las clases para probar las funciones / métodos que tenemos dentro de Helpers, Services, FormRequest, etc.

Dentro de Feature y Unit deberemos crear una estructura de carpetas que refleje la de la aplicación, por ejemplo, Si tenemos una clase "Dates" en el directorio "app/Helpers", crearíamos la clase de prueba con:

php artisan make:test app/Helpers/DatesTest --unit
¿Qué debemos probar y cómo?

En este caso voy a tratar de responder a las preguntas ¿Qué debemos probar? y ¿Cómo debemos probarlo?, difíciles de separar y también de responder.

Existen pruebas muy genéricas, por ejemplo, queremos saber si hay usuarios en la base de datos y sí, existe registrado un email determinado. Para ello usaríamos dos aserciones consecutivas, yendo de una más general a otra más específica.

Cuidado, si somos puristas, hay cosas que no deberían hacerse con pruebas unitarias, éstas no deberían acceder a la BD (deben de ser "independientes" y rápidas).

Comprobar la existencia de usuarios o un email, es necesario para el funcionamiento del sistema debido a los requisitos de la aplicación o sus características, ¿pueden englobarse dentro de las pruebas de características?, si y no, ya que no cubren características completas... En realidad, vamos a probar una fracción de una prueba de características.

Voy a poner mi ejemplo dentro de Unit, aunque no sea "estrictamente" pruebas unitarias.

Primero creo la clase:

php artisan make:test app/Models/UserTest --unit

Obtengo esto:


<?php

namespace Tests\Unit\app\Models;

use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{

    /**
     * A basic unit test example.
     *
     * @return  void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

Voy a cambiar la sentencia use inicial y escribiré 2 aserciones, cada una en una prueba. Además, uso setUp() para obtener al inicio todos los usuarios registrados.


<?php

namespace Tests\Unit\app\Models;

use Tests\TestCase;
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{

    public function setUp(): void
    {
        parent::setUp();

        $this->users = User::all();
    }

    public function test_has_users()
    {
        $result = ($this->users->count() > 0);
        $this->assertTrue($result);
    }

    public function test_some_user_has_the_email()
    {
        $email = 'foo@ironwoods.es';
        $userEmails = $this->users
            ->pluck('email')
            ->toArray();

        $this->assertContains($email, $userEmails);
    }
}

Pasar estas pruebas es un paso previo a probar un sistema de autenticación u otros que requieran usuarios / emails, como una lista de subscriptores ¿ves que acabo de mencionar dos features. Lo tendremos en cuenta al ordenar nuestras pruebas.

Habitualmente, iremos de una prueba general a otras más específicas, por lo que se requiere cierto orden en la disposición de las aserciones dentro de la clase.

En mi ejemplo si se han borrado todos los usuarios, no hace falta llegar a la segunda aserción, podría borrarse el usuario con el email a verificar, o cambiar este, esto no hace fallar la primera aserción.

Si hemos identificado una prueba unitaria y el método a probar no es lo suficientemente sencillo, es decir requieren varias pruebas unitarias, requiere una refactorización.

Otras pruebas en Laravel

Hay otros tipos de pruebas que es interesante automatizar, por ejemplo, las acciones que generalmente hacemos sobre las vistas una y otra vez, pulsar un botón, un enlace, comprar un producto, etc.

Podemos hacer pruebas e2e sobre las vistas con diferentes herramientas.

El paquete, Laravel Dusk, disponible desde Laravel 5.4, "extiende" las pruebas unitarias y puede usar como alternativa a Selenium o Cypress, que pueden usarse en otros desarrollos fuera de Laravel y tienen más opciones de testeo, pero también complejidad.

Cuando vemos ejemplos de pruebas en Laravel con aserciones como: assertTitle() o assertSee(), se trata de pruebas con Laravel Dusk.

Para instalar Laravel Dusk:

php artisan dusk:install

Cuando creemos pruebas Dusk, se crearán en el nuevo directorio "tests/Browser/", pero esa es otra historia...