"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Conseils pour tester les tâches en file d'attente dans Laravel

Conseils pour tester les tâches en file d'attente dans Laravel

Publié le 2024-11-05
Parcourir:116

Lorsque vous travaillez avec des applications Laravel, il est courant de rencontrer des scénarios dans lesquels une commande doit effectuer une tâche coûteuse. Pour éviter de bloquer le processus principal, vous pouvez décider de décharger la tâche vers une tâche pouvant être traitée par une file d'attente.

Prenons un exemple. Imaginez la commande app:import-users doit lire un gros fichier CSV et créer un utilisateur pour chaque entrée. Voici à quoi pourrait ressembler la commande :

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

Dans cet exemple, la commande distribue une tâche pour gérer la lecture du fichier et la création des utilisateurs. Voici à quoi pourrait ressembler le fichier 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'],
            ]);
        }
    }
}

Lors du test de cette fonctionnalité, un test typique de la commande pourrait ressembler à ceci :

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

À première vue, ce test semble fonctionner parfaitement. L'exécution de la suite de tests affiche un résultat positif :

Tips for testing queued jobs in Laravel

Exécution dans le monde réel

Cependant, lorsque vous exécutez la commande app:import-users dans un environnement réel, vous pouvez obtenir un résultat inattendu :

Tips for testing queued jobs in Laravel

Comme vous pouvez le voir, le résultat de la commande indique qu'il y a 0 utilisateur dans la base de données. Alors, pourquoi cela arrive-t-il ?

La raison est que le travail est distribué dans une file d'attente, il ne s'exécute donc pas de manière synchrone avec l'exécution de la commande. Les utilisateurs seront créés uniquement lorsque la file d'attente traitera le travail ultérieurement.

Pourquoi le test réussit-il ?

La suite de tests utilise le pilote de file d'attente de synchronisation par défaut, ce qui signifie que les tâches sont traitées de manière synchrone pendant le test. En conséquence, le travail s'exécute immédiatement, donnant l'idée que tout fonctionne comme prévu.

Bien que ce comportement soit acceptable dans l'environnement de test, il est important de reconnaître que les résultats réels dépendent de la configuration QUEUE_CONNECTION dans votre environnement de production. Et compte tenu des exigences de votre projet, vous savez peut-être que le travail sera traité dans une file d'attente asynchrone.

Une fois que vous aurez pris conscience de cette distinction, vous souhaiterez peut-être améliorer vos tests pour éviter les « faux positifs ».

Tester votre travail est expédié

Tout d'abord, il est important de vérifier que la commande distribue réellement la tâche, que la tâche soit traitée de manière synchrone ou asynchrone. Voici comment tester cela :

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

Le test de votre travail est traité

Une fois que vous avez confirmé que la tâche est distribuée, vous pouvez tester le travail réel effectué par la tâche dans un test distinct. Voici comment vous pouvez structurer le test pour le poste :

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

Cela garantit que la tâche effectue le travail nécessaire, qu'elle soit traitée par une file d'attente ou de manière synchrone.

Gestion des cas extrêmes

Comme dans la vraie vie, des cas extrêmes peuvent survenir et vous devez vous y préparer.

Le système de file d'attente de Laravel, selon la configuration de vos travailleurs, réessayera les tâches lorsqu'une exception se produit, et si les tentatives sont dépassées, la tâche sera marquée comme ayant échoué.

Alors, que se passe-t-il si le fichier n'existe pas ? Vous devez gérer de tels cas extrêmes en validant les entrées et en lançant des exceptions si nécessaire.

Voici comment vous pourriez gérer cela dans votre travail :

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

Voici comment tester ce scénario :

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

Réflexions finales

Cette approche garantit que vos tests reflètent plus précisément la manière dont les tâches seront traitées dans le monde réel.
La même stratégie peut être appliquée lorsqu'un contrôleur distribue une tâche dans une file d'attente ou lorsqu'un écouteur d'événement est mis en file d'attente.
Comme toujours, ajustez ces pratiques en fonction de votre projet et de votre équipe.

J'aimerais connaître votre avis !

Déclaration de sortie Cet article est reproduit sur : https://dev.to/eduarguz/tips-for-testing-queued-jobs-in-laravel-4c77?1 En cas d'infraction, veuillez contacter [email protected] pour le supprimer.
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3