35 votes

Travail retardé non traité dans rspec

J'essaie d'exécuter rspecs pour un travail différé personnalisé (GetPage::GetPageJob), mais j'ai un problème.

Lorsque je les exécute, les jobs sont bien mis en file d'attente (c'est à dire bien insérés dans la table delayed_jobs), mais ils ne sont pas traités par le job worker. En effet, après avoir lancé "rake jobs:work RAILS_ENV=test" dans un premier terminal, et après avoir exécuté les specs dans un second terminal, je ne vois aucune sortie du job worker dans le premier terminal.

En revanche, les travaux sont bien traités si je les mets en file d'attente via "script/console test". Je suis donc un peu perdu.

Avec les spécifications et la console script, la ligne que j'utilise pour mettre mes travaux en file d'attente est :

Delayed::Job.enqueue GetPage::GetPageJob.new("http://cnn.com")

Une idée ?

96voto

fearless_fool Points 9190

La façon la plus simple de tester les tâches Delayed::Job en file d'attente dans RSpec est de les exécuter en temps réel. Il suffit d'ajouter la ligne suivante à vos tests RSpec :

Delayed::Worker.delay_jobs = false

Ainsi, vos travaux seront traités immédiatement après leur mise en file d'attente, et non dans un thread séparé. C'est généralement ce que vous voulez pour les tests, car c'est déterministe.

Deux mises en garde

  • Si vous essayez de tester les erreurs de timing, les conditions de course, etc., cette approche ne vous aidera pas (puisque les travaux sont traités dans le même thread que RSpec).

  • La version actuelle de delayed_job (2.1.4) a un bug mineur dans lequel les crochets de rappel (enqueue, before, success, error, failure) ne sont pas appelés quand Delayed::Worker.delay_jobs est définie comme fausse.

Deux solutions de contournement

Si vous devez tester les crochets de rappel, je connais deux solutions de rechange :

  • Récupérer la dernière branche master depuis github. (Je n'ai pas essayé cela car j'ai besoin d'une version stable)

  • Au lieu de définir Delayed::Worker.delay_jobs = false Pour cela, appelez explicitement le mécanisme d'exécution de DJ dans votre code de test comme suit :

    successes, failures = Delayed::Worker.new.work_off

Il traitera tout ce qui se trouve dans la file d'attente des tâches (là encore, dans le même thread que les tests RSpec) et renverra deux nombres : le nombre de tâches qui ont réussi et le nombre de tâches qui ont échoué. J'utilise actuellement cette approche et elle fait tout ce dont j'ai besoin.

6 votes

Votre réponse est très intelligente, complète et bien documentée :). Merci, vous avez fait ma journée :)

0 votes

Qu'en est-il de :attempts ? Comment le tester ?

0 votes

@oma : Je vous ai peut-être mal compris, mais les valeurs de retour [succès, échecs] tiennent compte des :tentatives : un travail n'échoue pas réellement tant que le nombre de :tentatives n'est pas dépassé.

3voto

nmunson Points 705

Vous devrez lancer le processus de travail depuis l'intérieur de vos tests plutôt que depuis un autre processus. Essayez :

worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
worker.work_off

3voto

Jesse Wolgamott Points 30552

Dans le passé, j'ai essayé de faire un test de bout en bout de la logique -> travail différé -> exécuter le travail, et c'était trop de choses. Je pense que plutôt que de tester tout ça en utilisant RSpec, vous pourriez vous concentrer sur le test de chaque aspect.

Donc, testez qu'un travail est inséré. Ensuite, il y a un autre test qui teste ce qui doit se passer lorsqu'un travail est exécuté.

Vous pouvez également simuler le travail retardé, de sorte que lorsque vous mettez un travail en file d'attente, il est exécuté immédiatement.

0 votes

J'ai trouvé votre dernière phrase très utile ; je fais tout simplement l'un ou l'autre, par ex. UserMailer.stub(delay: UserMailer) o obj.stub(delay: obj) et mes tests se déroulent joyeusement. Bien que la suggestion de faire cela dans la configuration Delayed::Worker.delay_jobs = !Rails.env.in?(['development', 'test']) fonctionnerait aussi, j'ai tout un tas d'anciens tests qui testent les travaux retardés eux-mêmes et que je ne veux pas mettre à jour pour le moment. Merci !

1voto

drinor Points 730

J'utilise l'option de configuration pour exécuter les travaux en temps réel :

# config/initializers/delayed_job_config.rb
Delayed::Worker.delay_jobs = !Rails.env.test?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X