Configuración de Relaciones en Laravel usando Testing
Resumen
¿Cómo establecer relaciones entre un repositorio y un usuario en Laravel?
Al desarrollar aplicaciones con Laravel, una parte clave es configurar adecuadamente las relaciones entre los distintos modelos. Una relación común es la de un repositorio que pertenece a un usuario. Esto se logra mediante pruebas unitarias, lo que no solo ayuda a mantener el código ordenado, sino también a asegurar que las configuraciones sean precisas y eficientes. ¡Veamos cómo hacerlo!
¿Cómo crear una prueba para la relación?
Para empezar a configurar las relaciones, lo primero es crear una prueba en Laravel. Aquí se muestra cómo organizar y crear un archivo de prueba para uninear el repositorio con el usuario:
php artisan make:test Models/RepositoryTest
Este comando crea una estructura organizada para las pruebas en la carpeta Models, lo que ayuda a mejorar la organización general del proyecto.
¿Cómo manejar la lógica de la configuración?
Entonces, la lógica sigue los pasos tradicionales de desarrollo, donde si un archivo ya existe, uno sigue extendiendo su funcionalidad. Si no, se crea uno nuevo, que en este caso es RepositoryTest. Permitiendo esto comprobar que los repositorios pertenecen correctamente a los usuarios.
Crear un registro: Mediante la Factory se crea un repositorio falso para probar la asignación a un usuario.
Verificar la asignación: Se asegura de que el repositorio creado es una instancia del usuario adecuado.
¿Cómo implementar el método de relación?
Para enlazar el repositorio con el usuario, se necesita definir el método correspondiente en el modelo del repositorio:
Este método belongsTo establece que un repositorio está vinculado a un usuario específico, contrario a métodos como hasMany que indican que un usuario podría tener múltiples repositorios.
¿Cómo configurar la Factory y la migración?
Además de la relación, es esencial configurar tanto la Factory como las migraciones. Esta configuración garantiza que cada vez que se cree un repositorio, automáticamente se asigne un usuario:
Factory:
'user_id'=>User::factory(),
Esto indica que al crear un repositorio, se creará un usuario mediante User::factory(), lo que asegura que siempre existirá un enlace válido entre ambos.
Aquí se añade el user_id al esquema del repositorio y se establece que este es una clave foránea que referencia al id del usuario.
¿Cómo asegurarse de que todo funciona?
Las pruebas son un aliado invaluable en este proceso:
Ejecutar pruebas: Cada modificación en la estructura debe ir acompañada de pruebas que verifiquen que el sistema sigue funcionando adecuadamente.
Errores y ajustes: Si ocurren errores como la falta de configuración en la base de datos para el entorno de prueba, ajustes en unidades como el archivo phpunit.xml pueden ser necesarios para definir el entorno testing.
Las pruebas unitarias no solo facilitan el desarrollo ordenado, sino que juegan un papel crucial en el aseguramiento de la calidad del software. Realiza estos pasos con confianza, y tu aplicación Laravel estará lista para manejar relaciones complejas de manera eficiente.
Un ejercicio que recomiendo mucho es escuchar los promeros segundos de la clase para saber que es lo que se va a hacer en la clase y luego intentar hacerlo por nosotros mismos. Al finalizar (habiendolo logrado o no) ponemos en video completo.
En mi caso tuve el problema de COULD NOT FIND DRIVER PRAGMA, con windows 11 y xampp.
La solución es sencilla se debe editar el archivo php.ini descomentando las lineas de sqllite y sqllite3 posteriormente importe a RefreshDatabase y ambos test pasarón
Excelente! Gracias por tu aporte, me ahorraste mucho tiempo.
Al que le pueda servir, si están desarrollando con Laragon, para encontrar el archivo fácilmente, pueden ir a la parte de menú > php > php.ini
2024
en la migracion 2024_03_21_063346_create_reposiroties_table.php
Me salee este error. ayudaaaaaa
FAIL Tests\Unit\Models\RepositoryTest
⨯ belongs to user
FAIL Tests\Unit\Models\UserTest
⨯ has many repositories
• Tests\Unit\Models\RepositoryTest > belongs to user
Illuminate\Database\QueryException
could not find driver (SQL: PRAGMA foreign_keys = ON;)
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:678
674▕ // If an exception occurs when attempting to run a query, we'll format the error
675▕ // message to include the bindings with SQL, which will make this exception a
676▕ // lot more helpful to the developer instead of just the database's errors.
677▕ catch (Exception $e) {
➜ 678▕ throw new QueryException(
679▕ $query, $this->prepareBindings($bindings), $e
680▕ );
681▕ }
682▕
• Tests\Unit\Models\UserTest > has many repositories
Illuminate\Database\QueryException
could not find driver (SQL: PRAGMA foreign_keys = ON;)
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:678
674▕ // If an exception occurs when attempting to run a query, we'll format the error
675▕ // message to include the bindings with SQL, which will make this exception a
676▕ // lot more helpful to the developer instead of just the database's errors.
677▕ catch (Exception $e) {
➜ 678▕ throw new QueryException(
679▕ $query, $this->prepareBindings($bindings), $e
680▕ );
681▕ }
682▕
Tests: 2 failed
Time: 0.40s
Debes habilitar las extensiones sqlite3 and pdo_sqlite en tu php.ini
Lograste solucionarlo? Me sale el mismo problema
bueno con la creacion de bd real en mysql si jalo, pero como lo hizo el profe no me jalo..
Fíjate de agregar el trait RefreshDatabase, a mi me pasaba lo mismo y lo pude resolver.
Te dejé los comentarios en el código debajo.
<?php
namespace Tests\Unit\Models;use App\Models\User;use Illuminate\Database\Eloquent\Collection;use Tests\TestCase;use Illuminate\Foundation\Testing\RefreshDatabase;//Acá agregar este useclassUserTestextendsTestCase{ use RefreshDatabase;//Y también acápublicfunctiontest_has_many_repositories(){ $user =newUser; $this->assertInstanceOf(Collection::class, $user->repositories);}}
A mi me funcionó perfecto como lo hizo el profesor, hay veces son solo pequeños errores que no se detectan fácilmente.
Cuando me sucede que no me quiere funcionar, voy al link del repositorio de los ejercicios y copio los archivos que se modificaron en la clase y me ha funcionado.
si les da error ejecutando el test diciendo que no existe la tabla o la base de datos y tienen el archivo phpunit.xml y .env.testing tambien ejecuten php artisan config:clear porque las pruebas deberia de funcionar en sqlite con la memoria ram.
nota: php artisan optimize no funciona para este caso tiene que ser config:clear
Hola! como puedo borrar la cache de mi phpunit.xml
Sigue apuntando a mi base de datos configurada en mi archivo .env...
FAILED Tests\Unit\Models\RepositoryTest > belongs to user Error
Maximum call stack size of 8355840 bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion?
Dejo por aqui este aporte doble:
Si son varias clases (archivos de prueba) los que van a tener acceso a la base de datos, el trait RefreshDatabase se puede hacer directamente en el archivo TestCase, para no tener que usarlo en cada archivo de prueba.
El trait para RefreshDatabse se puede hacer de manera perezosa, es decir solamente hara el refresh si el test lo requiere de lo contrario pasara por alto.
archivo TestCase.php:
<?php
namespace Tests;use Illuminate\Foundation\Testing\LazilyRefreshDatabase;use Illuminate\Foundation\Testing\TestCaseasBaseTestCase;abstract classTestCaseextendsBaseTestCase{ use CreatesApplication; use LazilyRefreshDatabase;}
Yo estoy usando php artisan test --filter RepositoryTest para testear uno a uno.
Como ya habían mencionado en otro aporte: Si ya tienes las migraciones hechas y conectadas a tu base de datos local y no a SQLite,
O te saió este error:
PHPUnit\Framework\ExceptionWrapper SQLSTATE\[HY000]\[1045] Access denied for user 'root'@'localhost'(using password: NO)(SQL: insert into...
Y eso permitirá que puedas conectarte a la SQLite DB.
Si incluso luego de haber hecho eso te sale:
PHPUnit\Framework\ExceptionWrapper could not find driver(SQL:PRAGMA foreign_keys =ON;)```Entonces es porque no tienes el módulo SQLite3 en PHP
Entonce tienes que instalar php-sqlite3. En mi caso, como estoy usando PHP 8.3 en ubuntu sería:
`sudo apt install php8.3-sqlite3`Luego te saldrá el mismo error que le salió al profesor, simplemenete puedes poner```php
// ...use Illuminate\Foundation\Testing\RefreshDatabase;classRepositoryTestextendsTestCase{ use RefreshDatabase;// ....```
Yo me encontré con varios errores en el camino, no copies y pegues el código git del profesor, solo compara, muchas veces es solo tipeo, o que faltan llamadas de las clases, etc... y esto es normal ya que aun no hay costumbre sobre el framework.
Al final tomaras mas experiencia corrigiendo estos errores, y se te ira haciendo mas fácil pasando el tiempo...
El test pasa en verde aun sin indicar en la migración de repositories que 'user_id' es clave foranea. Entiendo que debe ser porque en la aserción que realizamos no valoramos como se guarda dicha relación en la base de datos. Mi pregunta es si esto es válido así porque mas adelante se vaya a comprobar que dichas relaciones a nivel de base de datos se guardan adecuadamente. Muchas gracias de antemano.
El paquete "Laravel Extre Intellisense" y "Laravel Extension Pack" te provee una funcion para importar las clases automaticamente !