Cómo testear páginas que reciben datos por post desde una solicitud HTTP generada al enviar un formulario.
En nuestro aprendizaje sobre el testing de aplicaciones en Laravel hemos podido aprender cosas básicas como la verificación de solicitudes get. Esas solicitudes son bastante fáciles de construir, puesto que no reciben ningún dato del usuario, simplemente hay que definir la URL de la página que queremos testear.
En este paso vamos a ir un poquito más allá, aprendiendo a testear páginas que reciben datos por post de un formulario. Gracias a las funcionalidades de test incorporadas en el framework Laravel veremos que testear este tipo de páginas es en realidad prácticamente tan sencillo como testear las solicitudes get.
Crear una solicitud HTTP de tipo post en un test
Comencemos aprendiendo a crear una solicitud por POST en un método de test. Para comenzar crearemos nuestra clase de test usando Artisan.
php artisan make:test TimeStoreTest
A partir de aquí doy por sabido el comando de Artisan y no lo volveré a mencionar a no ser que tenga alguna personalización que se deba realizar.
Como podrás imaginarte, si existía un método llamado get()
que creaba una llamada HTTP por get, existirá un método post()
que haga lo propio para simular el envío de datos de un formulario.
$response = $this->post('/panel/store', $formData);
Igual que vimos para get, el método post()
nos devuelve una instancia de un objeto que almacenamos en $response
, que luego usaremos para realizar nuestras aserciones. La única diferencia en este caso es que el método post()
recibe un segundo argumento que es el array asociativo con los datos que queremos que se envíen en esta solicitud de prueba.
El método de prueba podría tener un aspecto como este.
<?php
namespace Tests\Feature;
use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class TimeStoreTest extends TestCase
{
#[Test]
public function time_store_shows_received_time(): void
{
$formData = [
'start_hour' => '08',
'start_minute' => '15',
];
$response = $this->post('/panel/store', $formData);
$response->assertStatus(200);
$response->assertSee('08:15');
}
}
Como ves, estamos probando que una vez enviados los datos por post vamos a recibir un status code 200
.
Además estamos dando por hecho con esta prueba que en el contenido de la página que nos devuelva el servidor estará escrito el valor del dato que se le está pasando en un formato determinado.
Cómo testear que se le pasan los datos a la vista
Para seguir aprendiendo aserciones ofrecidas para el test de funcionalidades de Laravel, en nuestra clase de prueba podríamos añadir ahora un nuevo método de test que se encargase de verificar que ciertos datos se envían a la vista.
#[Test]
public function time_store_sends_correct_data_to_the_view(): void
{
$formData = [
'start_hour' => '08',
'start_minute' => '15',
];
$response = $this->post('/panel/store', $formData);
$response->assertViewIs('panel.show-time');
$response->assertViewHas('time', '08:15');
}
En este caso realizamos dos aserciones, la primera para verificar que se está usando la vista esperada y la segunda para verificar que le estamos pasando los datos adecuados desde el controlador, en este caso un dato llamado "time
" que tendrá un valor "08:15
".
Si tuviéramos que verificar que la vista tiene varios valores enviados, de una sola vez, podríamos usar el método
assertViewHasAll()
.
Solamente para que quede como referencia, voy a dejar el código que estaríamos testeando, que por cierto podrías construir perfectamente después de las pruebas, para ajustarte a las prácticas de TDD.
Esta sería la ruta:
Route::post('/panel/store', [ActivityController::class, 'store']);
Este sería el código de nuestro controlador:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ActivityController extends Controller
{
public function store(Request $request)
{
// 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]);
}
}
Evidentemente, nuestro controlador podría ser más complejo en el caso que quisiéramos validar los datos y devolver los posibles errores de validación. No obstante, por no complicar los test hemos preferido mantener las cosas simples y ver todo el proceso de validaciones un poco más adelante.
Por último la vista podría verse así:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mostrar el tiempo</title>
</head>
<body>
<div>
<h1>Mostrar el tiempo</h1>
<p>El tiempo seleccionado es: <strong>{{ $time }}</strong></p>
<a href="{{ url('/panel') }}">Volver</a>
</div>
</body>
</html>
Asertar una redirección
En muchas ocasiones al desarrollar una funcionalidad de envío de formulario el controlador, después de recibir los datos por post y hacer lo que deba de hacer con ellos, reenviará a otra página. Este es el comportamiento habitual cuando almacenamos algo en la base de datos, por ejemplo. Después de guardar los datos el controlador reenviará al usuario a la página donde va a mostrar aquel registro recién creado.
Por ejemplo, supongamos que una vez que se haya recibido el dato el controador nos envía al dashboard, con un código como este:
return redirect('/dashboard');
En un caso como este, en el código de prueba querremos hacer una aserción para verificar esa redirección. Esto se consigue con el método assertRedirect()
. Este método puede o no recibir un argumento, que sería la URL a la que queremos verificar que nos lleva esa redirección.
Si no recibe nada simplemente verificará el status code, que sea generalmente el 302. Pero en el caso que sepas dónde ta va a llevar la redirección, como en este ejemplo, podemos indicar su URL.
$response->assertRedirect('/dashboard');
De momento eso es todo. En este artículo has aprendido a testear una página que recibe un formulario. En el siguiete artículo aprenderás a testear el formulario en sí, que es algo más relacionado con el testeo de vistas.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...