如何使用Resque和Rspec示例来桥接测试?

时间:2011-02-28 11:30:37

标签: rspec resque

在与Rspec示例并行实现Resque时,我感到很困惑。 以下是一个昂贵的方法.generate(self)的类     class 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

完美无缺。但我有两个问题。

之前,我的示例规范用于测试整个.generate(self)方法的堆栈。但是现在我把它推进到Resque工作中,我如何能够将我的示例连接起来以使相同的测试变为绿色而不会孤立?或者我必须隔离测试??

最后,如果我有10个工作岗位,我是否必须使用self.perform方法创建10个单独的工作类?

3 个答案:

答案 0 :(得分:33)

测试这样的异步内容总是很棘手。我们所做的是:

  • 在我们的功能测试中,我们确保作业入队。使用mocha或类似的东西通常就足够了。如果要运行测试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

<击>

从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工作的聪明方法。这些都是为我工作的。

答案 1 :(得分:8)

使用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

答案 2 :(得分:1)

您必须进行两项不同的测试。一个用于验证,以确保将作业排入Resque队列,第二个用于确保工作人员接收的队列中的作业正在满足您的要求。

不,你不需要编写10种不同的执行方法。当你运行Resque worker时,他们从队列中获取作业并盲目地调用你工作的.perform方法。所以,你的工作应该有执行方法。