Testing Hooks en Pest

Al trabajar en nuestros tests Pest, frecuentemente nos encontraremos con querer ejecutar un mismo código de preparación para múltiples tests. Por ejemplo, contar con un usuario ya creado en varios tests. En estos casos, Pest nos ofrece utilizar testing hooks.

Hooks beforeAll, beforeEach, afterEach y afterAll

Pest nos proporciona 4 testing hooks: beforeAll, beforeEach, afterEach y afterAll. Útiles para reutilizar un mismo preparativo a múltiples tests antes de ejecutarlos.

Creamos un test de prueba tests/Unit/PestHooksTest.php para mostrar el uso de estos testing hooks.

beforeAll(fn () => var_dump('Antes de todo'));
beforeEach(fn () => var_dump('Antes de cada uno'));
afterEach(fn () => var_dump('Después de cada uno'));
afterAll(fn () => var_dump('Después de todo'));

test('verdadero es verdadero', function () {
    $this->assertTrue(true);
});

test('falso es falso', function () {
    $this->assertFalse(false);
});

Ejecutamos nuestra prueba con artisan test y usamos el argumento filter para ejecutar solamente el test PestHooksTest.

artisan test --filter=PestHooksTest

El resultado nos devuelve lo siguiente.

string(13) "Antes de todo"
string(17) "Antes de cada uno"
string(20) "Después de cada uno"
string(17) "Antes de cada uno"
string(20) "Después de cada uno"
string(16) "Después de todo"

beforeAll se ha ejecutado al comienzo una sola vez. beforeEach y afterEach se han ejecutado dos veces. Al comenzar cada una de nuestros dos tests y al finalizar. afterAll se ha ejecutado al final una sola vez.

Algo a tomar en cuenta, es que los hooks beforeAll y afterAll no nos dan acceso a las funcionalidades de Laravel. Devolverá un error si intentamos acceder a Laravel desde estos hooks porque Laravel aún no ha sido inicializado en estos hooks.

Por ejemplo, si tenemos lo siguiente.

beforeAll(fn () => var_dump(config('app.name')));
afterAll(fn () => var_dump(config('app.name')));

test('verdadero es verdadero', function () {
    $this->assertTrue(true);
});

test('falso es falso', function () {
    $this->assertFalse(false);
});

Nos devolverá error.

Error en Pest Hook

Función uses

Pest también nos ofrece la función uses() para cuando queremos usar traits en nuestros tests.

Por ejemplo, para usar el trait RefreshDatabase. Un trait muy común que restablece nuestra base de datos antes de cada test.

use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('verdadero es verdadero', function () {
    $this->assertTrue(true);
});

test('falso es falso', function () {
    $this->assertFalse(false);
});

Así restablecemos la base de datos antes de ejecutar cada uno de nuestros dos tests.

El trait LazilyRefreshDatabase es otra opción para restablecer la base de datos. A diferencia de RefreshDatabase, LazilyRefreshDatabase no resetea la base de datos al ejecutar cada test. Si no que solamente la restablece hasta que un test use la base de datos. Ayudando a mejorar el rendimiento de los tests que no necesitan interactuar con la base de datos.

Este trait es perfecto para emplearlo en nuestro tests/TestCase.php base. Así, nos olvidamos de tener que usar RefreshDatabase en los archivos de test.

namespace Tests;

use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;
    use LazilyRefreshDatabase;
}