"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Dicas para testar jobs enfileirados no Laravel

Dicas para testar jobs enfileirados no Laravel

Publicado em 2024-11-05
Navegar:618

Ao trabalhar com aplicações Laravel, é comum encontrar cenários onde um comando precisa executar uma tarefa cara. Para evitar o bloqueio do processo principal, você pode decidir transferir a tarefa para um trabalho que possa ser processado por uma fila.

Vejamos um exemplo. Imagine que o comando app:import-users precisa ler um arquivo CSV grande e criar um usuário para cada entrada. Esta é a aparência do 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.');
    }
}

Neste exemplo, o comando despacha um job para tratar da leitura do arquivo e da criação de usuários. Esta é a aparência do 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'],
            ]);
        }
    }
}

Ao testar esse recurso, um teste típico para o comando pode ser assim:

/* 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);
    }
}

À primeira vista, este teste parece funcionar perfeitamente. A execução do conjunto de testes mostra um resultado bem-sucedido:

Tips for testing queued jobs in Laravel

Execução no Mundo Real

No entanto, ao executar o comando app:import-users em um ambiente real, você pode obter um resultado inesperado:

Tips for testing queued jobs in Laravel

Como você pode ver, a saída do comando indica que há 0 usuários no banco de dados. Então, por que isso acontece?

O motivo é que o trabalho é despachado para uma fila, portanto não é executado de forma síncrona com a execução do comando. Os usuários serão criados somente quando a fila processar o trabalho posteriormente.

Por que o teste passa?

O conjunto de testes usa o driver de fila de sincronização por padrão, o que significa que os trabalhos são processados ​​de forma síncrona durante o teste. Como resultado, o job é executado imediatamente, dando a ideia de que tudo funciona conforme o esperado.

Embora esse comportamento seja aceitável no ambiente de teste, é importante reconhecer que os resultados do mundo real dependem da configuração QUEUE_CONNECTION em seu ambiente de produção. E dados os requisitos do seu projeto, você deve saber que o trabalho será processado em uma fila assíncrona.

Depois de estar ciente dessa distinção, você pode querer melhorar seus testes para evitar “falsos positivos”.

Testar seu trabalho foi despachado

Primeiro, é importante verificar se o comando realmente despacha o trabalho, independentemente de o trabalho ser processado de forma síncrona ou assíncrona. Veja como testar isso:

/* 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);
    }
}

Testar seu trabalho é processado

Depois de confirmar que o trabalho foi enviado, você poderá testar o trabalho real executado pelo trabalho em um teste separado. Veja como você pode estruturar o teste para o trabalho:

/* 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);
    }
}

Isso garante que o trabalho execute o trabalho necessário, independentemente de ser processado por uma fila ou de forma síncrona.

Lidando com casos extremos

Como na vida real, casos extremos podem acontecer e você deve estar preparado para eles.

O sistema de filas do Laravel, de acordo com a configuração dos seus trabalhadores, tentará novamente os trabalhos quando ocorrer uma exceção e, se as tentativas forem excedidas, o trabalho será marcado como falhado.

Então, o que acontece se o arquivo não existir? Você precisa lidar com esses casos extremos validando entradas e lançando exceções quando necessário.

Veja como você pode lidar com isso em seu trabalho:

/* 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'],
            ]);
        }
    }
}

Veja como você testaria esse cenário:

/* 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());
    }
}

Considerações finais

Essa abordagem garante que seus testes reflitam com mais precisão como os trabalhos serão processados ​​no mundo real.
A mesma estratégia pode ser aplicada quando um controlador despacha um trabalho para uma fila ou onde um ouvinte de evento está na fila.
Como sempre, ajuste essas práticas para se adequarem ao seu projeto e equipe.

Eu adoraria ouvir sua opinião!

Declaração de lançamento Este artigo está reproduzido em: https://dev.to/eduarguz/tips-for-testing-queued-jobs-in-laravel-4c77?1 Se houver alguma infração, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3