> Manuales > Manual de Testing en Laravel

Cómo usar los Data Providers que nos ofrece el framework de testing PHPUnit, de modo que podamos ser mucho más concisos y completos al hacer los test de las validaciones realizadas en los controladores de Laravel.

Usar Data Providers de PHPUnit en los test de validaciones Laravel

En este artículo vamos a demostrar que puede resultar muy conveniente usar los Data providers de PHPUnit para verificar de una vez diversos juegos de valores de formulario, comprobando si han resultado válidos o no.

Solo que sirva de aclaración antes de comenzar: Este artículo del Manual de Testing con Laravel continúa el tema de testing de las validaciones, pero aplicando una mejora sustancial por medio de los "data providers", que nos aporta en realidad el framework de test PHPUnit.

Qué son los Data Providers de PHPUnit

Los data providers son algo específico de PHPUnit y básicamente consiste en un método que devuelve un array con un conjunto de juegos de datos. Estos juegos de datos se pueden usar para las pruebas, de modo que podamos alimentar un único método de test con todo el conjunto de datos de prueba. Gracias a ellos podemos conseguir que ese método de test se ejecute una vez por cada uno de los juegos de datos que hay en el array devuelto por el data provider.

Para conseguir usar un método de data provider en los métodos de test usaremos decoradores (o en las versiones nuevas de PHPUnit Atributos de PHP). De este modo declaramos que ciertos data providers serán usados en un método de test.

Será el framework de test (PHPUnit) el que se encargue de realizar la invocación de ese método para cada uno de los elementos del array del data provider. Dado que Laravel usa PHPUnit podemos beneficiarnos de los data providers en las pruebas de Features dentro del framework Laravel.

No voy a explicar con detalle porque no es el objetivo de este artículo pero sí lo necesitas tienes un artículo donde puedes encontrar explicaciones detalladas de los data providers de PHPUnit.

Usando Data Providers para el test de las validaciones en Laravel

Vamos a ver el código de un data provider que define los juegos de datos con los que queremos probar las validaciones.

public static function validDataProvider(): array {
    return [
        [
            ['start_hour' => '00', 'start_minute' => '00'],
        ],
        [
            ['start_hour' => '23', 'start_minute' => '45'],
        ],
        [
            ['start_hour' => '01', 'start_minute' => '30'],
        ],
        [
            ['start_hour' => '12', 'start_minute' => '15'],
        ],
    ];
}

Y ahora podemos ver cómo se usa el data provider en el método de test.

#[Test]
#[DataProvider('validDataProvider')]
public function submited_data_has_no_validation_errors($formData): void
{
    $response = $this->post('/panel/store', $formData);

    $response->assertValid();
}

El método estático validDataProvider() es lo que sería el data provider, mientras que el método submited_data_has_no_validation_errors() es el que usa el data provider.

Lo bueno de usar datas providers es que no repetimos código en los métodos de test y que, si queremos añadir un nuevo juego de datos para probarlo también, solamente tienes que agregar un nuevo elemento en el array del data provider.

Ten en cuenta que es necesario importar el atributo DataProvider en tus clases de pruebas con el correspondiente use PHPUnit\Framework\Attributes\DataProvider.

Cómo mejorar los Data providers con etiquetado de los casos de prueba

Podríamos si lo deseamos cambiar un poco la sintaxis del data provider para etiquetar el nombre de cada uno de los juegos de datos, de modo que la salida proporcionada al ejecutar las pruebas sea más descriptiva. En este caso el método del data provider quedaría así:

public static function validDataProvider(): array {
    return [
        '00:00' => [
            ['start_hour' => '00', 'start_minute' => '00'],
        ],
        '23:45' => [
            ['start_hour' => '23', 'start_minute' => '45'],
        ],
        '01:30' => [
            ['start_hour' => '01', 'start_minute' => '30'],
        ],
        '12:15' => [
            ['start_hour' => '12', 'start_minute' => '15'],
        ],
    ];
}

Definiendo también los errores de validación en un data provider

Ya para acabar vamos a ver otro ejemplo de data provider para verificar que determinados juegos de datos nos deberían dar errores de validación.

El código del data provider en este caso se complica un poco porque necesitamos enviarle dos argumentos en la llamada a la función que hace el test. El primer argumento sería el juego de datos que nosotros queremos enviar al controlador y el segundo parámetro son los errores que esperamos recibir en cada uno de los juegos de datos usados.

public static function invalidDataProvider(): array
{
    return [
        'hour is missing' => [
            'formData' => [
                'start_minute' => '15',
            ],
            'expectedErrors' => ['start_hour'],
        ],
        'minute is invalid' => [
            'formData' => [
                'start_hour' => '08',
                'start_minute' => '10',
            ],
            'expectedErrors' => ['start_minute' => 'The selected start minute is invalid.'],
        ],
        'hour is out of range' => [
            'formData' => [
                'start_hour' => '25',
                'start_minute' => '15',
            ],
            'expectedErrors' => ['start_hour' => 'The start hour field format is invalid.'],
        ],
    ];
}

Luego, el método que realiza el test queda muy compacto y expresivo.

#[Test]
#[DataProvider('invalidDataProvider')]
public function submited_data_has_validation_errors($formData, $expectedErrors): void
{
    $response = $this->post('/panel/store', $formData);

    $response->assertinValid($expectedErrors);
}

Controlador que realiza las validaciones

Solo para que quede como referencia, escribo a continuación el código del controlador actualizado, en el que se han añadido las reglas de validación necesarias para que las pruebas anteriores funcionen correctamente.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ActivityController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'start_hour' => [
                'required',
                'regex:/^(0?[0-9]|1[0-9]|2[0-3])$/', // Permite valores de 0 a 23
            ],
            'start_minute' => 'required|in:00,15,30,45',
        ]);

        // Construir la cadena de tiempo en formato hh:mm
        $time = $request->input('start_hour') . ':' . $request->input('start_minute');

        // Pasar la cadena a la vista
        return view('panel.show-time', ['time' => $time]);
    }
}

Conclusión

Con esto hemos visto cómo puedes probar las validaciones de los controladores Laravel de manera compacta con los Data Providers. Como has podido ver gracias a las aserciones disponibles en Laravel es muy fácil realizar los tests de las validaciones y con los data providers hacer baterías de test muy completas.

En el siguiente artículo vamos a seguir analizando algunas funcionalidades de los tests de solicitudes HTTP que tenemos disponibles en el framework para comprobar controladores que esperan ciertos valores en elementos como las sesiones o las cookies.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual