如何将使用Resque的测试与Rspec示例联系起来?

如何将使用Resque的测试与Rspec示例联系起来?,rspec,resque,Rspec,Resque,在与Rspec示例并行实现Resque时,我感到困惑。 下面是一个使用昂贵方法的类。生成(self) 上课 ... ChangeGenerator.generate(自生成) ... 结束 在实现resque之后,上面的类更改为下面的类,并添加了ChangeRecorderJob类 class SomeClass ... Resque.enqueue(ChangeRecorderJob, self.id) ... end class ChangeRecorderJob @que

在与Rspec示例并行实现Resque时,我感到困惑。 下面是一个使用昂贵方法的类
。生成(self)
上课 ... 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
method创建10个单独的作业类?

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

  • 在我们的功能测试中,我们确保作业排队。用摩卡咖啡或类似的东西来满足期望通常就足够了。如果要运行测试redis服务器,可以验证队列是否正确以及作业参数是否正确。尽管您在测试Resque本身

  • 作业作为单元测试单独进行测试。因为它们只有一个名为
    perform
    的类方法,所以单元测试非常简单。在您的情况下,您需要测试ChangeRecorderJob.perform是否满足您的要求。我们倾向于测试作业是否在适当的队列中,作业的参数是否有效,以及作业是否符合我们的要求

  • 现在,一起测试所有东西是一个棘手的部分。我采用了两种不同的方法,每种方法都有优点和缺点:

    • Monkey patch Resqueue.enqueue要从resque 1.14.0开始同步运行作业,可以在初始值设定项中使用
      resque.inline=true
      ,而不是Monkey patch
    • 模拟一个工人从队列中弹出一个作业,并实际在一个分叉的进程中运行
同步运行作业是两者中最容易的一种。您只需在spec\u助手中加载以下内容:

module Resque alias_method :enqueue_async, :enqueue def self.enqueue(klass, *args) klass.new(0, *args).perform end end 在让工人将工作从队列中弹出时有一点延迟。当然,您需要运行一个测试redis服务器,以便工作人员有一个队列可以弹出


我相信其他人已经想出了聪明的方法来测试新工作。这些都是对我有效的方法。

你必须做两个不同的测试。一个用于排队,以确保将作业排队到重新排队队列中,另一个用于确保在工人拾取队列中的作业时,按照您的要求执行

不,您不需要编写10种不同的执行方法。当您运行Resque workers时,他们会从队列中拾取作业并盲目调用。对您的作业执行方法。因此,您的工作应该具有perform方法。

用于单元测试

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个jobs类,每个类都有一个
。在每个类中执行
方法。这3份工作是针对同一型号的。因此,如何在单个作业类中编写这3个
.perform
,而不是编写3个单独的作业类呢?
perform
方法使用varargs。如果愿意,您可以添加一个鉴别器值,然后您的单个
perform
就可以分派给提供所需功能的任何方法。
Resque.inline=true
是一个聪明的解决方案,但正如您所指出的,它可能会使事情变得缓慢,我遇到过一些运行它的粗心代码的情况同步运行与异步运行的结果不同。如果Resque有一个测试助手,您可以在其中执行诸如
Resque.last_job
Resque.process之类的调用,那就太酷了,和
Resque.clear
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