Cómo construir una API REST de Laravel con desarrollo basado en pruebas

Hay una cita famosa de James Grenning, uno de los pioneros en metodologías de desarrollo TDD y Agile:

Si no está haciendo un desarrollo basado en pruebas, está haciendo un desarrollo posterior a la depuración - James Grenning

Hoy emprenderemos un viaje de Laravel impulsado por pruebas. Crearemos una API REST de Laravel completa con autenticación y funcionalidad CRUD sin abrir Postman o un navegador. ?

Nota: Este tutorial asume que comprende los conceptos básicos de Laravel y PHPUnit. ¿Si lo tienes fuera del camino? Manejemos.

Configurar el proyecto

Comience creando un nuevo proyecto de Laravel con composer create-project --prefer-dist laravel/laravel tdd-journey.

A continuación, tenemos que ejecutar el scaffolder autenticación que usaríamos, seguir adelante y ejecutar php artisan make:autha continuación php artisan migrate.

En realidad, no usaremos las rutas y vistas generadas. Para este proyecto, estaríamos usando jwt-auth. Así que adelante, configúrelo en su aplicación.

Nota: Si tiene errores con el generatecomando de JWT , puede seguir esta solución hasta que se agregue a la versión estable.

Finalmente, puede eliminar ExampleTestlas carpetas tests/Unity tests/Featurepara que no interfiera con los resultados de nuestra prueba y estamos listos para comenzar.

Escribiendo el código

  1. Comience estableciendo su authconfiguración para usar el controlador JWT como predeterminado:

Luego agregue lo siguiente a su routes/api.phparchivo:

2. Ahora que tenemos nuestro controlador configurado, configure su modelo de usuario de la misma manera:

Lo que hicimos fue que implementamos JWTSubjecty agregamos los métodos requeridos.

3. A continuación, debemos agregar nuestros métodos de autenticación en el controlador.

Ejecute php artisan make:controller AuthControllery agregue los siguientes métodos:

Este paso es bastante sencillo, todo lo que hacemos es agregar los métodos authenticatey registera nuestro controlador. En el authenticatemétodo, validamos la entrada, intentamos iniciar sesión y devolvemos el token si tiene éxito. En el método de registro, validamos la entrada, creamos un nuevo usuario con la entrada y generamos un token para el usuario basado en eso.

4. Luego, en la parte buena. Probando lo que acabamos de escribir. Genere las clases de prueba usando php artisan make:test AuthTest. En el nuevo tests/Feature/AuthTestagregue estos métodos:

Los comentarios en el código anterior describen bastante bien el código. Una cosa que debe tener en cuenta es cómo creamos y eliminamos al usuario en cada prueba. El objetivo de las pruebas es que deben ser independientes entre sí y que el estado de la base de datos es ideal.

Ahora ejecútelo $vendor/bin/phpunito $ phpunitsi lo tiene instalado globalmente. Ejecutar eso debería darte afirmaciones exitosas. Si ese no fue el caso, puede revisar los registros, corregir y volver a probar. Este es el hermoso ciclo de TDD.

5. Ahora que tenemos nuestra autenticación funcionando, agreguemos el elemento para CRUD. Para este tutorial, usaremos recetas de comida como nuestros artículos CRUD, porque, ¿por qué no?

Comience creando nuestra migración php artisan make:migration create_recipes_tabley agregue lo siguiente:

Luego, ejecute la migración. Ahora agregue el modelo usando php artisan make:model Recipey agregue esto a nuestro modelo.

Luego agregue este método al usermodelo.

6. Ahora necesitamos puntos finales para administrar nuestras recetas. Primero, crearemos el controlador php artisan make:controller RecipeController. A continuación, edite el routes/api.phparchivo y agregue el createpunto final.

En el controlador, agregue el método de creación también

Genere la prueba de características php artisan make:test RecipeTesty edite el contenido como en:

El código se explica por sí mismo. Todo lo que hacemos es crear un método que maneja el registro de un usuario y la generación de tokens, luego usamos ese token en el testCreate()método. Tenga en cuenta el uso del RefreshDatabaserasgo, el rasgo es la forma conveniente de Laravel de restablecer su base de datos después de cada prueba, que es perfecta para nuestro pequeño proyecto ingenioso.

Bien, por ahora, todo lo que queremos afirmar es el estado de la respuesta, adelante y ejecute $ vendor/bin/phpunit.

Si todo va bien, debería recibir un error. ?

There was 1 failure:
1) Tests\Feature\RecipeTest::testCreateExpected status code 200 but received 500.Failed asserting that false is true.
/home/user/sites/tdd-journey/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:133/home/user/sites/tdd-journey/tests/Feature/RecipeTest.php:49
FAILURES!Tests: 3, Assertions: 5, Failures: 1.

Al observar los archivos de registro, podemos ver que el culpable es la relación publishery recipesen las clases Recipey User. Laravel intenta encontrar una user_idcolumna en la tabla y usarla como clave externa, pero en nuestra migración la configuramos publisher_idcomo clave externa. Ahora, ajuste las líneas como se muestra a continuación:

//Recipe filepublic function publisher(){ return $this->belongsTo(User::class,'publisher_id');}
//User filepublic function recipes(){ return $this->hasMany(Recipe::class,'publisher_id');}

Y luego vuelva a ejecutar la prueba. ¡Si todo va bien, obtenemos todas las pruebas ecológicas! ?

... 3 / 3 (100%)
...
OK (3 tests, 5 assertions)

Ahora todavía tenemos que probar la creación de la receta. Para ello podemos afirmar el recuento de recetas del usuario. Actualice su testCreatemétodo como en:

Ahora podemos seguir adelante y completar el resto de nuestros métodos. Es hora de algunos cambios. Primero, nuestroroutes/api.php

A continuación, agregamos los métodos al controlador. Actualiza tu RecipeControllerclase de esta manera.

El código y los comentarios ya explican la lógica en buena medida.

Lastly our test/Feature/RecipeTest

Other than the additional test, the only other difference was adding a class-wide user file. That way, the authenticate method not only generates a token, but it sets the user file for subsequent operations.

Now run $ vendor/bin/phpunit and you should have all green tests if done correctly.

Conclusion

Hopefully, this gave you an insight into how TDD works in Laravel. It is definitely a much wider concept than this, one that is not bound to a specific method.

Though this method of development may seem longer than the usual debug laterprocedure, it’s perfect for catching errors early on in your code. Though there are cases where a non-TDD approach is more useful, it’s still a solid skill and habit to get used to.

The entire code for this walkthrough is available on Github here. Feel free to play around with it.

Cheers!