Pruebas con Pest/PHPUnit en Laravel
Anteriormente creamos todas estas pruebas mediante PHPUnit, pero, en Laravel tenemos otro framework para realizar las pruebas disponibles como lo es Pest; a términos prácticos, tienen más similitudes que diferencia y a medida que vayamos traduciendo las pruebas realizadas anteriormente con PHPUnit, veremos como diferencia fundamental, una sintaxis más simple, limpia y expresiva y en general, más moderna.
Es importante mencionar que en un proyecto en Laravel, podemos emplear PHPUnit y/o Pest sin hacer ningún cambio, el archivo clave en para PHPUnit es:
tests\TestCase.php
Y para Pest:
tests\Pest.php
Es importante también recordar que al momento de crear un proyecto en Laravel, se pregunta cuál framework quieres emplear, y es es el empleado por defecto al momento de ejecutar el comando de:
$ laravel new <ProyectName>
También podemos especificar mediante una opción si queremos crear la prueba para PHPUnit:
$ php artisan make:test <Class>Test --unit
O Pest:
$ php artisan make:test <Class>Test --pest
Con Pest, no empleamos clases, tenemos métodos como el siguiente:
test('performs sums', function () {
$result = sum(1, 2);
expect($result)->toBe(3);
});
Como alternativa a la función test(), Pest proporciona la conveniente función it() que simplemente antepone la descripción de la prueba con la palabra "it", haciendo que sus pruebas sean más legibles:
it('performs sums', function () {
$result = sum(1, 2);
expect($result)->toBe(3);
});
Finalmente, podemos agrupar pruebas relacionadas:
describe('sum', function () {
it('may sum integers', function () {
$result = sum(1, 2);
expect($result)->toBe(3);
});
it('may sum floats', function () {
$result = sum(1.5, 2.5);
expect($result)->toBe(4.0);
});
});
}
Más información en:
https://pestphp.com/docs/writing-tests
En todos los casos, en las funciones anteriores, definimos un texto representativo a la acción a probar mediante la prueba, por ejemplo:
performs sums
Pruebas Unitarias con Pest
Las pruebas con Pest no cambian mucho de las implementadas con PHPUnit, es una sintaxis un poco más simple y a continuación, se presenta las pruebas traducidas anteriormente con Pest:
tests/Feature/Api/CategoryTest.php
<?php
use App\Models\Category;
test('test all', function () {
Category::factory(10);
$categories = Category::get()->toArray();
$this->get(
'/api/category/all',
[
'Authorization' => 'Bearer ' . generateTokenAuth()
]
)->assertOk()->assertJson($categories);
});
it("test get by id", function () {
Category::factory(1)->create();
$category = Category::first();
$this->get('/api/category/' . $category->id, [
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(200)->assertJson([
'id' => $category->id,
'title' => $category->title,
'slug' => $category->slug
]);
});
it("test get by slug", function () {
Category::factory(1)->create();
$category = Category::first();
$this->get('/api/category/slug/' . $category->slug, [
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(200)->assertJson([
'id' => $category->id,
'title' => $category->title,
'slug' => $category->slug
]);
});
it("test post", function () {
$data = ['title' => 'Cate 1', 'slug' => 'cate-2-new'];
$this->post('/api/category', $data, [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(200)->assertJson($data);
});
it("test post error form title", function () {
$data = ['title' => '', 'slug' => 'cate-2-new'];
$response = $this->post('/api/category', $data, [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(422);
// $this->assertStringContainsString("The title field is required.", $response->getContent());
$this->assertMatchesRegularExpression("/The title field is required./", $response->getContent());
// $testArray = array("a"=>"value a", "b"=>"value b");
// $value = "value b";
// // assert function to test whether 'value' is a value of array
// $this->assertContains($value, $testArray) ;
// $this->assertContains("The title field is required.",['title'=>'["The title field is required."]']);
});
it("test post error form slug", function () {
$data = ['title' => 'cate 3', 'slug' => ''];
$response = $this->post('/api/category', $data, [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(422);
// $response->assertStringContainsString("The slug field is required.", $response->getContent());
$this->assertMatchesRegularExpression("/The slug field is required./", $response->getContent());
});
it("test post error form slug unique", function () {
Category::create(
[
'title' => 'category title',
'slug' => 'cate-3'
]
);
$data = ['title' => 'cate 3', 'slug' => 'cate-3'];
$response = $this->post('/api/category', $data, [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(422);
$this->assertStringContainsString("The slug has already been taken.", $response->getContent());
});
it("test get by id 404", function () {
$this->get('/api/category/1000', [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(404)->assertContent('"Not found"');
});
it("test get by slug 404", function () {
$this->get('/api/category/slug/cate-not-exist', [
'Accept' => 'application/json',
])->assertStatus(404)->assertContent('"Not found"');
});
it("test put", function () {
Category::factory(1)->create();
$categoryOld = Category::first();
$dataEdit = ['title' => 'Cate new 1', 'slug' => 'cate-1-new'];
$this->put('/api/category/' . $categoryOld->id, $dataEdit, [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(200)->assertJson($dataEdit);
});
it("test delete auth", function () {
Category::factory(1)->create();
$category = Category::first();
$this->delete('/api/category/' . $category->id,[], [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->generateTokenAuth()
])->assertStatus(200)
->assertContent('"ok"');
$category = Category::find($category->id);
$this->assertEquals($category, null);
});
Al ser recursos protegidos por autenticación, definimos el método para generar el token dentro del a clase Pest:
tests/Pest.php
uses(TestCase::class, RefreshDatabase::class)->in('Feature');
function generateTokenAuth()
{
User::factory()->create();
return User::first()->createToken('myapptoken')->plainTextToken;
}
En el archivo anterior, también puedes ver que tienen el trait de RefreshDatabase que empleamos antes con PHPUnit.
Transcripción vídeo
Felicidades si llegaste hasta esta clase que según tengo yo aquí al menos lo que yo grabé inicialmente no sé si luego grabé alguna clase intermedia Pero al menos para lo que yo grabé la primera vez esta sería la clase 63 sin contar la introducción si contamos la introducción sería la clase 64 entonces bueno si llegaste hasta este punto bueno un enorme felicidades y si Bueno si viste la primera y de repente viste pes y viniste acá y y sería la segunda clase que estás viendo de igual manera Felicidades.
PHP Unit, el framework para testing moderno
Qué es básicamente es lo mismo que php unit pero en este caso con otra tecnología es como si te diga View y rea es decir son dos tipos de framework que tenemos para realizar pruebas unitarias cada una tiene su ventajas desventaja y ahí puedes bueno Buscar la interpretación de muchas personas yo lo veo un poco te lo explico como yo lo veo php Unit sería como que el enfoque más antiguo el original yp sería un enfoque un poco más moderno y esto lo vamos a ver un poco más cuando veamos un poco su sintaxis es decir puedes ver que es una sintaxis un poco más moderna más limpia más bonita más organizada es decir quitamos las clases y lo demás eso viene siendo una prueba por lo demás a lo que se refiere los métodos de aserción que aquí es la estrella de las pruebas es más o menos lo mismo vamos a ir haciéndolo Pero tenemos al menos muchos que son similares Bueno aquí no dejé ninguno o si no aquí tengo uno aquí puedes ver el método de aserción que también tenemos el acer json pero en este caso Recuerda que estamos empleando es Pest y no el de php unit a la final es más o menos lo mismo vamos a ver también cómo bueno generar el token ya que es decir dónde podemos colocar este tipo de métodos que vamos a emplear en múltiples lugares de las pruebas luego vamos a ir viéndolo eso poco a poco entonces bueno seguramente lo que te está preocupando es que y te lo voy a responder de una Sí vamos a hacer las mismas pruebas que hicimos antes pero en este caso con pes Entonces serían otras 60 clases más bueno no vamos a manejarlo de esa forma ya que vamos a hacer las primeras y luego a partir de ahí Simplemente yo las implemento y te voy mostrando y explicando un poquito el código ya que bueno ya veo un poco exagerado hacer otra vez 60 clases al menos para hacer todo con pes si ya tiene una estructura muy similar y simplemente lo hago más que todo por bueno para que veas otra posible implementación empleando otro framework y bueno un poco esto porque otra vez es uno de los posibles candidatos que tenemos cuando creamos un proyecto en larabel Recuerda que cuando creamos un proyecto en laravel nos pregunta fuerza Si queremos emplear php unit o si queremos emplear pes y bueno en este caso otra vez por ser el más tradicional emplee php unit inicialmente es decir porque es como que la referencia y ahorita bueno Por más que sea considero importante emplear pest que se le la forma más moderna entonces para que tengas ambos puntos de vista y cuando quieres implementar un proyecto y tú decidas cuál quieras emplear o dependiendo de las necesidades e de la persona que te solicita el proyecto.
Laravel, soporte para Pest y PHPUnit
Entonces al menos sepas cómo arrancar la buena noticia es que podemos emplear sin ningún problema tanto pes como php unit en el mismo proyecto otra vez sin ningún problema aquí lo único que yo he visto es la diferencia si seleccionamos uno u otro Cuando creamos el proyecto es que cuando creamos la prueba ya automáticamente se genera a partir la prueba a partir de la tecnología seleccionada es decir si hubiéramos colocado php unit tal cual yo hice con este proyecto entonces automáticamente crear la prueba la prueba se crea en php unit si hubiéramos seleccionado pest se crea con pest pero no pasa nada también podemos crear una prueba en una tecnología de esta un estos framework en específico simplemente aquí colocando la opción de —pest o —unit que lo crean sus respectivos frameworks es decir uno va a crear la clase y el otro va a crear una plantilla Como vistes antes por lo demás sería Exactamente lo mismo y bueno nosotros para cuestiones de prueba simplemente vamos a comentar en cada uno de los frameworks o de los proyectos que trabajamos vamos a comentar las pruebas anteriores o las quitamos de la carpeta de test para hacer las pruebas más limpias y ver exactamente qué es lo que está pasando y cómo funciona así que es un poco eso lo que te quería comentar e Bueno inicialmente si vamos a crear las primeras pruebas o la primera Prueba con pes y luego a partir de ahí vamos a otra vez hacer rápido voy a hacerla terminar de implementar la clase o el archivo aparte y luego a partir de ahí te voy explicando qué fue lo que hice o al menos hacerte una rápida Introducción a la mismo para no alargar esto demás ya que a la final ya completamos esto en la cual ya hicimos o probamos el proceso completo de cabar rabo resapi y también aquí la parte del dashboard probamos cada uno de esos módulos Y bueno ya no tenemos más nada que probar ya que otra vez no vamos a probar módulos que son o que forman parte del framework así que pues nada Eso era lo que te quería comentar Ah bueno también importante que era lo que te menciono un poquito por aquí al igual que para ver si lo encuentro al igual que con php unit.
Pest.php y TestCase.php
Tenemos un archivo llamado test Case para precisamente poder hacer las conexiones es decir ahí tenemos el código Laravel en pest También tenemos una clase llamada pest aquí la puedes ver si no las tienes no pasa nada puedes generarte otro proyecto y copiarlo aquí o también puedes ir a mi repositorio y del proyecto y copiar este esta clase para que la puedas tener Y si porque si no cuando vayas a hacer una petición de tipo get, post delete y toda la cuestión te va a dar un error y te va a indicar que no lo reconoce por lo demás aquí también te voy adelantando creo que lo dejé aquí.
Al colocar Aunque es lo hice Perdón en el de en el de la Rest API que es el primero que otra vez vamos a trabajar aquí perfectamente tú puedes colocar que lo borré Bueno después lo coloco otra vez aquí puedes colocar método para generar el token de autenticación que era el que empleamos inicialmente y es a partir de la prueba que es la única que implementado por acá pero eso ya lo vemos A partir de la siguiente clase otra cositas importantes de Test antes de terminar es un poco su sintaxis aquí podemos emplear una función llamada Test en la cual aquí colocamos que lógicamente representativo al nombre de la función es decir aquí directamente colocamos el nombre de la función quitamos los que bajo porque no serían necesarios y es lo que pudiéramos colocar acá aparte de Test también podemos emplear otro método llamado it() que funciona De igual forma y bueno para poder agrupar las pruebas También tenemos uno llamado describe() y por aquí colocamos las pruebas que son relacionadas. Por ejemplo si quisiéramos crear en un solo archivo para el dashboard pudiéramos hacerlo y creamos ahí sería uno por cada módulo y en cada uno de esos, colocamos las pruebas para cada uno de estos bueno de estos módulos eso pudiera ser o directamente creamos un archivo aparte como tú quieras pero bueno al menos tenemos esa ventaja para organizar un poquito nuestras pruebas si no quedan ahí tan regadas bueno eso es lo principal realmente como te digo a la final son otra vez otro framework muy similar al que vimos anteriormente tiene más relaciones que diferencia claro está así que pues nada sin más que decir ahora sí vamos a la siguiente clase la cual vamos a comenzar a crear nuestras pruebas con pest.
- Andrés Cruz
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter