Algunas veces se presentan proyectos que nos complican las cosas, y uno de esos escenarios, sería el hacer en Laravel Testing con múltiples bases de datos y seeders y realizando integración continua en Gitlab.
Contenidos
Nuestra aplicación necesita mas de una conexión o base de datos. Esto en local no tiene problema. EL problema se complica, porque tenemos que usar Gitlab CI con Gitlab Runners y tiene que haber mas de una base de datos, y la imagen oficial de Mysql para Docker no permite de más de una base de datos, aunque hay posibilidades de hacerlo al final, ¿no es matar la mosca a cañonazos?
En determinados escenarios, sin seeding la cosa es más sencilla. Te avisaremos a lo largo del desarrollo.
Para hacer Laravel Testing en un proyecto los datos deben ser adaptados a tu conexión local, de producción, etc. No hagas copy & paste sin leer y comprender lo que haces. Si lo deseas hay un artículo anterior, Laravel Ci con gitlab, Docker Runner, MySQL 8 y PHP 7.3 que podría ayudarte a comprender el mecanismo para trabajar con Gitlab CI
Aquí necesitamos varias cosas:
Para ello haremos uso de las configuración, las variables de entorno, y los prefijos, siendo estos últimos los que nos permitirán trabajar con una sola base de datos, de forma fácil.
Los elementos entre <> son para personalizar y los que no pueden personalzarse pero siendo cuidadosos y personalizarlos igual en cada lugar. Un equivoco puede dar mucho squebraderos de cabeza
return [ 'default' => env('DB_CONNECTION', 'mysql'), 'connection_1' => env('DB_CONNECTION_1', 'db1'), 'connection_n' => env('DB_CONNECTION_N', 'dbn'), 'connections' => [ 'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => env('DB_PREFIX', ''), 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], 'db1' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE_1', 'forge'), 'username' => env('DB_USERNAME_1', 'forge'), 'password' => env('DB_PASSWORD_1', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => env('DB_PREFIX_1', ''), 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], 'dbn' => ...
Ahora también necesitaremos las entradas para la conexiones de testing en memoria con sqlite.
// PHPunit testing main connection 'testing' => [ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'default_', ], // PHPunit testing audit connection 'testing_1' => [ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'db1_', ],
Ahora editaremos nuestro fichero .env para nuestra app
DB_CONNECTION=mysql DB_HOST=<host> DB_PORT=<3306> DB_DATABASE=<database> DB_USERNAME=<user> DB_PASSWORD=<PaSsWoRd> DB_PREFIX=<db0_> DB_CONNECTION_VMAIL=connection_1 DB_HOST_VMAIL=<host> DB_PORT_VMAIL=<3306> DB_DATABASE_VMAIL=<database2> DB_USERNAME_VMAIL=<user2> DB_PASSWORD_VMAIL=<PaSsWoRd2> DB_PREFIX_VMAIL=<db1_> ...
DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=database_test DB_USERNAME=<user> DB_PASSWORD=<PaSsWoRd> DB_PREFIX=<prefixdb0_> DB_CONNECTION_VMAIL=connection_1 DB_HOST_VMAIL=mysql DB_PORT_VMAIL=3306 DB_DATABASE_VMAIL=database_test DB_USERNAME_VMAIL=<user> DB_PASSWORD_VMAIL=<PaSsWoRd> DB_PREFIX_VMAIL=<prefixdb1_>
Al momento de escribir este artículo no encontré mejor forma de hacer Laravel Testing con estas características y estaba algo saturado, así que es muy posible que exista un mejor método de mejorar las modificaciones en las migraciones.
El proceso propuesto, pasa por indicar en cada clase de migraciones cual es la conexión a usar, y esto lo haremos así, usando en el constructor la asignación de la conexión y modificando la forma en la que usamos el método create(), haciéndolo desde la clase heredada Schema:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; class CreateUsersTable extends Migration { protected $schema; public function __construct() { $this->schema = Schema::connection(config('database.default')); } public function up() { $this->schema->create('users', function (Blueprint $table) { $table->bigIncrements('id'); . . . . . . $table->timestamps(); }); } public function down() { $this->schema->dropIfExists('users'); } }
En el caso de una migración con otra conexión usaríamos el valor adecuado en la construcción de la clase
public function __construct() { $this->schema = Schema::connection(config('database.connection_1')); }
En el relleno de datos usando seeding debemos tener en cuenta la conexion sobre la que trabajamos en cada sembrador
// Ejemplo 1 public function run() { DB::connection(config('database.default'))->table('admin')->insert([... // Ejemplo 2 public function run() { DB::connection(config('database.db1'))->table('insecondb')->insert([...
Puede ser que por necesidad necesitemos hacer sembrado desde un fichero sql. Esto nos obliga a tener dos ficheros .sql ya que la clausula INSERT INTO en un caso deberá tener el nombre de la tabla conforme a producción, y otra conforme a testing en Gitlab CI con otro prefijo
<?php use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; //use Illuminate\Support\Facades\DB; class DbSchemasSeeder extends Seeder { public function run() { if (env('DB_HOST') == 'mysql') { $sql = file_get_contents(database_path('seeds/fichero_para_testing.sql')); DB::connection(config('database.db1'))->statement($sql); } else { $sql = file_get_contents(database_path('seeds/fichero_para_local.sql')); DB::connection(config('database.default'))->statement($sql); } } }
Gracias a Bolduc por su imagen tomada de Unsplash y a Canva por su app para editar
Comparte este articulo en
¡Hola a todos! Vamos a sumergirnos en el fascinante mundo de Mod Security y aprender…
Ya son muchos años en el sector, muchos años pasando por varios paneles de control,…
La lista UCEPROTECT es una herramienta utilizada por muchos administradores de sistemas y proveedores de…
No es la primera vez que me encuentro con el agotamiento de la memoria en…
Descubre cómo solucionar problemas de acceso a servidores con Centos 7, Almalinux 8, Ubuntu 20.04…
Uno de los mensajes más alarmantes que puedes encontrarte es aquel que indica que tu…