"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Consejos para probar trabajos en cola en Laravel

Consejos para probar trabajos en cola en Laravel

Publicado el 2024-11-05
Navegar:256

Cuando se trabaja con aplicaciones Laravel, es común encontrar escenarios en los que un comando necesita realizar una tarea costosa. Para evitar bloquear el proceso principal, puede decidir descargar la tarea a un trabajo que pueda ser procesado por una cola.

Veamos un ejemplo. Imagine el comando app:import-users necesita leer un archivo CSV grande y crear un usuario para cada entrada. Así es como podría verse el comando:

/* ImportUsersCommand.php */

namespace App\Console\Commands;

/*...*/

class ImportUsersCommand extends Command
{
    protected $signature = 'app:import-users';

    public function handle()
    {
        dispatch(new ImportUsersJob());

        $this->line('Users imported successfully.');
        $this->line('There are: ' . User::count(). ' Users.');
    }
}

En este ejemplo, el comando envía un trabajo para manejar la lectura del archivo y la creación de usuarios. Así es como podría verse ImportUsersJob.php:

/* ImportUsersJob.php */

namespace App\Jobs;

/*...*/

class ImportUsersJob implements ShouldQueue
{
    public function handle(FileReader $reader): void
    {   
        foreach($reader->read('users.csv') as $data) {
            User::create([
                'name' => $data['name'], 
                'email' => $data['email'],
            ]);
        }
    }
}

Al probar esta característica, una prueba típica para el comando podría verse así:

/* ImportUsersCommandTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersCommandTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_processes_the_file(): void
    {
        Storage::fake('local')->put('users.csv', "...");

        $this->artisan('app:import-users')
            ->expectsOutput('Users imported successfully.')
            ->expectsOutput('There are: 10 Users.')
            ->assertSuccessful();

        $this->assertDatabaseCount('users', 10);
    }
}

A primera vista, esta prueba parece funcionar perfectamente. La ejecución del conjunto de pruebas muestra un resultado exitoso:

Tips for testing queued jobs in Laravel

Ejecución en el mundo real

Sin embargo, cuando ejecutas el comando app:import-users en un entorno real, es posible que obtengas un resultado inesperado:

Tips for testing queued jobs in Laravel

Como puede ver, el resultado del comando indica que hay 0 usuarios en la base de datos. Entonces, ¿por qué sucede esto?

El motivo es que el trabajo se envía a una cola, por lo que no se ejecuta sincrónicamente con la ejecución del comando. Los usuarios se crearán solo cuando la cola procese el trabajo más adelante.

¿Por qué pasa la prueba?

El conjunto de pruebas utiliza el controlador de cola de sincronización de forma predeterminada, lo que significa que los trabajos se procesan sincrónicamente durante la prueba. Como resultado, el trabajo se ejecuta inmediatamente, dando la idea de que todo funciona como se esperaba.

Si bien este comportamiento es aceptable en el entorno de prueba, es importante reconocer que los resultados del mundo real dependen de la configuración QUEUE_CONNECTION en su entorno de producción. Y dados los requisitos de su proyecto, es posible que sepa que el trabajo se procesará en una cola asíncrona.

Una vez que sea consciente de esta distinción, es posible que desee mejorar sus pruebas para evitar "falsos positivos".

Se envía la prueba de su trabajo

Primero, es importante verificar que el comando realmente envíe el trabajo, independientemente de si el trabajo se procesa de forma sincrónica o asincrónica. Aquí se explica cómo probarlo:

/* ImportUsersCommandTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersCommandTest extends TestCase
{    
    public function test_it_dispatches_the_job(): void
    {
        Queue:fake();

        $this->artisan('app:import-users')
            ->expectsOutput('Process has been queued.')
            ->assertSuccessful();

        Queue::assertPushed(ImportUsersJob::class);
    }
}

Probando que su trabajo esté procesado

Una vez que haya confirmado que el trabajo se envió, puede probar el trabajo real realizado por el trabajo en una prueba separada. Así es como podrías estructurar la prueba para el puesto:

/* ImportUsersJobTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersJobTest extends TestCase
{
    use refreshDatabase;

    public function test_it_processes_the_file()
    {
        Storage::fake('local')->put('users.csv', "...");

        app()->call([new ImportUsersJob(), 'handle']);

        $this->assertDatabaseCount('users', 10);
    }
}

Esto garantiza que el trabajo realice el trabajo necesario, independientemente de si se procesa mediante una cola o de forma sincrónica.

Manejo de casos extremos

Como en la vida real, pueden ocurrir casos extremos y debes estar preparado para ellos.

El sistema de cola de Laravel, de acuerdo con la configuración de sus trabajadores, reintentará los trabajos cuando ocurra una excepción y, si se exceden los reintentos, el trabajo se marcará como fallido.

Entonces, ¿qué pasa si el archivo no existe? Debe manejar estos casos extremos validando las entradas y lanzando excepciones cuando sea necesario.

Así es como podrías manejar esto en tu trabajo:

/* ImportUsersJobTest.php */

namespace App\Jobs;

/*...*/

class ImportUsersJob implements ShouldQueue
{
    use Queueable;

    public function handle(FileReader $reader): void
    {   
        if(!Storage::disk('local')->exists('users.csv')){
            throw new Exception('The users.csv file doesn\'t exist.')
        }

        foreach($reader->read('users.csv') as $data) {
            User::create([
                'name' => $data['name'], 
                'email' => $data['email'],
            ]);
        }
    }
}

Así es como probarías este escenario:

/* ImportUsersJobTest.php */

namespace Tests\Feature;

/*...*/

class ImportUsersJobTest extends TestCase
{
    use refreshDatabase;

    /*...*/

    public function test_it_fails_when_file_doesnt_exist(): void
    {
        Storage::fake('local');

        $this->expectException(Exception::class);
        $this->expectExceptionMessage('The users.csv file doesn\'t exist.');

        dispatch(new ImportUsersJob());
    }
}

Pensamientos finales

Este enfoque garantiza que sus pruebas reflejen con mayor precisión cómo se procesarán los trabajos en el mundo real.
Se puede aplicar la misma estrategia cuando un controlador envía un trabajo a una cola o cuando un detector de eventos está en cola.
Como siempre, ajuste estas prácticas para que se ajusten a su proyecto y equipo.

¡Me encantaría escuchar tu opinión!

Declaración de liberación Este artículo se reproduce en: https://dev.to/eduarguz/tips-for-testing-queued-jobs-in-laravel-4c77?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3