> Manuales > Manual de Testing en Laravel

Testing en Laravel de las excepciones tratadas por el propio framework Laravel para los casos de errores comunes de HTTP, como 404 o 500.

En Laravel podemos probar situaciones que deberían levantar excepciones de diversos tipos. Ya empezamos a revisarlas en el pasado artículo dedicado a Pruebas con excepciones en los test con Laravel y en esta ocasión vamos a profundizar abordando los casos más sencillos, que serían las excepciones típicas de HTTP, que son gestionadas de manera automática por el framework, como la página no encontrada o el acceso prohibido a ciertas funcionalidades.

Este tipo de excepciones se prueban de manera muy fácil ya que hay métodos específicos para crear aserciones específicas para ellas. Vamos a ver algunos ejemplos y algunas personalizaciones que nos pueden resultar útiles.

Excepciones HTTP en pruebas Laravel

Crear una clase de test para probar excepciones de HTTP

Puede ser útil crear una clase de test específica para comprobar diversas situaciones especiales relacionadas con errores de HTTP comunes, como el intento de acceso a una página inexistente. Esa clase podría llamarse HTTPExceptionsTest.

En esta clase iremos colocando diversas pruebas, como las que mostraremos a continuación.

Probar la página error 404

Para probar la página de error 404 simplemente podemos intentar consultar con una página inexistente. Vamos a empezar por ahí, con un código de test como el que sigue.

<?php

namespace Tests\Feature;

use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;

class HTTPExceptionsTest extends TestCase
{
    #[Test]
    public function it_returns_404_for_nonexistent_routes()
    {
        $response = $this->get('/ruta-inexistente');

        $response->assertNotFound();
        $response->dump();
    }
}

Como puedes ver, tenemos un assertNotFound() que verifica que esa ruta inexistente devuelve el error que esperamos.

También podríamos haber usado la aserción assertStatus(404), que haría exactamente lo mismo.

Verificar una página de error 404 personalizada

Pero siempre es una buena idea personalizar las páginas de errores. Vamos a suponer que has cambiado la página de error 404 predeterminada del framework. Luego querrás verificar que esa página de error se está mostrando como debe.

Entonces podríamos personalizar la página de error. Para ello puedes crear el archivo resources/views/errors/404.blade.php, si es que no existe anteriormente en tu aplicación.

Nuestra página de error podría tener un código como este:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Página no encontrada</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            padding: 50px;
        }
        h1 {
            font-size: 3em;
            color: #e74c3c;
        }
        p {
            font-size: 1.5em;
            color: #555;
        }
        a {
            color: #3498db;
            text-decoration: none;
        }
        a:hover {
            text-decoration: underline;
        }
        .container {
            margin: 0 auto;
            max-width: 750px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>La página que buscas no existe en este sitio web</h1>
        <p>A esto lo llamamos error 404. Puede deberse a varios motivos, pero muchas veces es por escribir mal la dirección a la que se pretende acceder.</p>
        <a href="/">Ir a la portada de este sitio</a> o reporta el error en el formulario de contacto.
    </div>
</body>
</html>

Ahora vamos a transformar nuestro test para hacer una comprobación más exhaustiva, que incluya la verificación de algún contenido de la página de respuesta, así nos aseguramos de que se está usando la página personalizada de error 404 que hemos creado.

#[Test]
public function it_returns_404_for_nonexistent_routes()
{
        $response = $this->get('/ruta-inexistente');

        $response->assertNotFound();
        $response->assertSee('error 404');
        $response->assertSee('<a href="/">', false);
}

Probar páginas protegidas

Supongamos que tenemos una página protegida. Como no hemos aprendido a trabajar con usuarios vamos a pensar que simplemente necesita una cookie en el usuario para que se pueda acceder.

Si no tienes esa cookie esperamos obtener un error HTTP 403. En el caso que tengamos la cookie creada entonces nos deja pasar. Esto se podría verificar con un par de métodos de test.

#[Test]
public function it_returns_403_for_restricted_routes() {
    $response = $this->get('/ruta-restringida');

    $response->assertForbidden();
}

Este método verifica que una ruta te da un error 403 (Forbidden).

También podríamos enviar un $response->assertStatus(403).

El siguiente método tendrá que producir un estado adecuado para que la ruta restringida nos deje pasar. Para ello tendremos que generar una cookie y luego intentar acceder a la ruta restringida.

#[Test]
public function it_allows_access_if_user_cookie_is_valid() {
    // Este código lo mejoraremos cuando lleguemos a bases de datos porque no podemos escribir a fuego el token
    $response = $this->withCookie('my_token', value: 'un token valido')->get('/ruta-restringida');

    $response->assertOk();
}

Hemos hecho una cookie con el método withCookie() que ya conocemos de artículos anteriores. Luego hemos verificado que la ruta nos deja pasar con un assertOk().

También podríamos haber usado un assertStatus(200).

La prueba nos funcionará si tenemos el código de producción bien realizado. Solo que el valor de la cookie lo hemos escrito a fuego en el código de test. Esto no es una buena idea porque si fuera un token verídico alguien podría verlo. Así que el código de este ejemplo está "cogido con pinzas".

En futuros artículos vamos a ver una mejor manera de solucionar esta prueba haciéndola más adecuada y segura, pero tenemos que aprender antes cosas que no hemos abordado, como las bases de datos. Lo que habría que hacer sería crear una tabla con tokens válidos, o una tabla de usuarios. Entonces en nuestro código de pruebas creamos ese token antes de hacer el assert, o el usuario, para asegurarnos que la base de datos tiene un estado compatible con el acceso a la página restringida.

Testear un error 500

Los errores 500 también son testeables. Pueden ocurrir por un simple error de sintaxis o porque cierta situación provoque una excepción que no se está tratando, algo que quizás ocurra cuando se invoca una página de cierto modo o cuando un servicio al que estás intentando acceder esté caído. Quizás cuando un usuario intenta acceder a un recurso para el que no está autorizado.

Si simplemente queremos testear la respuesta HTTP ante cierta solicitud que produce un error 500, podemos proceder de la siguiente manera.

#[Test]
public function it_throws_exception_when_create_custom_activity(): void
{
    $response = $this->get('/pagina-que-causa-un-error');

    $response->assertInternalServerError();
}

Con este assert conseguimos verificar que ocurre un error 500 y los tests se darían por buenos.

También podríamos haber usado un assertStatus(500) con el mismo resultado.

Este error 500 lo puedes provocar con cualquier cosa que se te ocurra. Incluso un error de sintaxis PHP en un controlador haría que se produjera un error 500 y por lo tanto el test funcionase bien, aunque la página que estamos testeando fallase.

También puedes levantar una excepción con un código como este:

throw new \Exception("Error no esperado en el servidor");

Testear que se muestra la página de error 500 personalizada

Los errores 500 no son deseables pero a veces ocurren. Por eso podrías desear testear la página personalizada que se muestra a los usuarios en producción cuando ocurre un error 500.

Testear esta página personalizada de error 500 puede tener algunas dificultades extra, fundamentalmente porque si estas en modo debug no la vas a poder ver.

El modo debug es algo importante en modo desarrollo y se define en tu .env: APP_DEBUG=true. En pruebas también es interesante mantener el modo debug para que puedas ver los errores de tu código y saber por qué ocurren y cómo solucionarlos.

Así que lo normal para testear una página personalizada de error 500 sería pasar el modo debug a false y luego hacer los assertSee necesarios de tu modo debug.

#[Test]
public function it_throws_exception_when_create_custom_activity(): void
{
    config(['app.debug' => false]);
    $response = $this->get('/pagina-que-causa-un-error');

    $response->assertInternalServerError();
    $response->assertSee("Hemos tenido un error al procesar tu solicitud");
}

Así no te saldrá el código descriptivo del error como respuesta, sino la página de error 500 que hayas personalizado (archivo ``).

Ten en cuenta que un assertSee() cuando tienes un error de sintaxis o una excepción no tratada te puede mostrar el código de tu test, por lo que un assertSee() podría darte un falso positivo, porque aparezca en la salida de la página de debug del error. Si configuramos el debug a false esto no ocurrirá.

Podríamos validar otras excepciones de HTTP pero creo que de momento es suficiente con lo que hemos aprendido. En el siguiente artículo vamos a ver cómo validar ciertas excepciones personalizadas creadas por nosotros mismos.

Miguel Angel Alvarez

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

Manual