Как связать тестирование с помощью Resque с примерами Rspec? - PullRequest
22 голосов
/ 28 февраля 2011

У меня путаница при реализации Resque параллельно с примерами Rspec.Ниже приведен класс с дорогим методом .generate(self) class SomeClass ... ChangeGenerator.generate (self) ... end

После реализации resque вышеприведенный класс изменился на следующий и добавил класс ChangeRecorderJob.

class SomeClass
  ...
  Resque.enqueue(ChangeRecorderJob, self.id)
  ...
end

class ChangeRecorderJob
  @queue = :change_recorder_job

  def self.perform(noti_id)
    notification = Notification.find(noti_id)    
    ChangeGenerator.generate(notification)
  end
end

Работает отлично.Но у меня есть две проблемы.

Раньше моя примерная спецификация использовалась для тестирования всего стека метода .generate(self).Но теперь, когда я запустил это в работу Resque, как я могу соединить мои примеры, чтобы сделать тот же самый тест зеленым, не изолируя его?Или мне нужно изолировать тест ??

И, наконец, если у меня есть 10 заданий для постановки в очередь, нужно ли создавать 10 отдельных классов заданий с помощью метода self.perform?

Ответы [ 3 ]

33 голосов
/ 04 марта 2011

Тестирование таких асинхронных вещей всегда сложно.Что мы делаем:

  • В наших функциональных тестах мы проверяем, что задание ставится в очередь.Обычно достаточно употребления мокко или чего-то подобного с ожиданием.Если вы хотите запустить тестовый сервер Redis, вы можете проверить правильность увеличения очереди и правильность параметров задания.Хотя вы тестируете Resque себя немного в этот момент.

  • Задания тестируются изолированно как модульные тесты.Поскольку у них просто есть метод класса с именем perform, ваши модульные тесты довольно просты.В вашем случае вы должны проверить, что ChangeRecorderJob.perform делает то, что вы хотите.Мы склонны проверять, что задания находятся в соответствующей очереди, что параметры задания верны и что задание выполняет то, что мы хотим.

  • Теперь, чтобы проверить все вместе,сложная часть.Я сделал это двумя разными способами, и у каждого есть свои плюсы и минусы:

    • Monkey-patch Resqueue.enqueue для синхронного запуска задания Начиная с resque 1.14.0вы можете использовать Resque.inline = true в своем инициализаторе вместо патчей для обезьян
    • Имитировать работника, выталкивающего задание из очереди и фактически выполняемого в разветвленном процессе

Синхронный запуск задания намного проще.Вы бы просто загрузили что-то вроде следующего в ваш spec_helper:

module Resque
  alias_method :enqueue_async, :enqueue

  def self.enqueue(klass, *args)
    klass.new(0, *args).perform
  end
end

Начиная с версии 1.14.0 вы можете просто установить Resque.inline = true в инициализаторевместо обезьяны-исправления.Если вы застряли на более старой версии resque, необходим обезьян-патч.

Обратите внимание, что, поскольку вы работаете здесь синхронно, вы будете нести расходы на длительную работу.работа.Возможно, более важно то, что вы собираетесь работать в одном и том же процессе, так что это не совсем точное представление о том, как ваша работа будет выполняться.

Запускать работу в разветвленном рабочем режиме, очень похоже на resqueвам нужно будет сделать что-то вроде следующего:

def run_resque_job(job_class, job_args, opts={})
  queue = opts[:queue] || "test_queue"

  Resque::Job.create(queue, job_class, *job_args)
  worker = Resque::Worker.new(queue)
  worker.very_verbose = true if opts[:verbose]

  if opts[:fork]
    # do a single job then shutdown
    def worker.done_working
      super
      shutdown
    end
    worker.work(0.01)
  else
    job = worker.reserve
    worker.perform(job)
  end
end

Существует небольшая задержка в том, чтобы заставить работника выбросить задание из очереди.И, естественно, вам понадобится запустить тестовый сервер Redis, чтобы у работника была очередь, с которой нужно выскочить.

Я уверен, что другие люди придумали хитрые способы тестирования заданий Resque.Это то, что работает для меня.

8 голосов
/ 09 июня 2011

Используйте resque_spec для модульного тестирования.

describe "#recalculate" do
  before do
    ResqueSpec.reset!
  end

  it "adds person.calculate to the Person queue" do
    person.recalculate
    Person.should have_queued(person.id, :calculate).in(:people)
  end
end

А для интеграционных тестов:

describe "#score!" do
  before do
    ResqueSpec.reset!
  end

  it "increases the score" do
    with_resque do
      game.score!
    end
    game.score.should == 10
  end
end
1 голос
/ 04 марта 2011

Вам нужно будет сделать два разных теста.Один для запроса, чтобы убедиться, что задания ставятся в очередь в очереди Resque, а второй для того, чтобы убедиться, что задания в очереди, когда их забирают рабочие, выполняются в соответствии с вашими требованиями.Вам не нужно писать 10 различных методов исполнения.Когда вы запускаете сотрудников Resque, они выбирают задания из очереди и слепо вызывают метод .perform для вашей работы.Таким образом, ожидается, что ваша работа будет иметь метод перформанса.

...