Подтвердить что ты не робот

Как связать тестирование с помощью Resque с примерами Rspec?

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

После реализации 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

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

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

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

4b9b3361

Ответ 1

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

  • В наших функциональных тестах мы убеждаемся, что задание завершено. Обычно используется мокка или что-то подобное с ожиданием. Если вы хотите запустить тестовый сервер 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

Забастовкa >

С resque 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. Это то, что работает для меня.

Ответ 2

Используйте 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

Ответ 3

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

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