23

在将 Resque 与 Rspec 示例并行实施时,我感到困惑。下面是一个方法昂贵的.generate(self) 类类 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 个工作要入队,我是否必须使用self.perform方法创建 10 个单独的工作类?

4

3 回答 3

34

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

  • 在我们的功能测试中,我们确保作业被排队。使用 mocha 或类似的东西通常就足够了。如果你想运行一个测试 redis 服务器,你可以验证正确的队列增长并且作业参数是正确的。尽管您当时正在测试 Resque 本身。

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

  • 现在,一起测试所有东西是棘手的部分。我已经完成了这两种不同的方式,每种方式都有优点和缺点:

    • Monkey-patch Resqueue.enqueue 同步运行作业 从 resque 1.14.0 开始,您可以Resque.inline = true在初始化程序中使用而不是猴子补丁
    • 模拟工作人员从队列中弹出作业并实际在分叉进程中运行

到目前为止,同步运行作业是两者中更容易的。您只需在您的 spec_helper 中加载类似以下内容:

模块 Resque
  别名方法:入队异步,:入队

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

从 resque 1.14.0 开始,您可以Resque.inline = true在初始化程序中设置而不是猴子补丁。如果您卡在旧版本的 resque 上,则需要使用猴子补丁。

请注意,由于您在此处同步运行,因此您将承担长时间运行的工作的成本。也许更重要的是您将在同一进程中运行,因此它不能完全准确地表示您的工作将如何运行。

要在分叉的工作人员中运行作业,就像 resque 那样,您需要执行以下操作:

def run_resque_job(job_class, job_args, opts={})
  队列 = opts[:queue] || “测试队列”

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

  如果选择 [:fork]
    # 做一个工作然后关机
    def worker.done_working
      极好的
      关闭
    结尾
    工人工作(0.01)
  别的
    工作 = worker.reserve
    worker.perform(工作)
  结尾
结尾

让工作人员将作业从队列中弹出会稍有延迟。当然,您需要运行一个测试 redis 服务器,以便工作人员有一个可以退出的队列。

我敢肯定,其他人已经想出了测试 resque 工作的聪明方法。这些都是为我工作的。

于 2011-03-04T13:41:18.927 回答
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
于 2011-06-09T16:05:20.757 回答
1

你将不得不做两个不同的测试。一个用于排队,以确保作业被排入 Resque 队列,第二个用于确保队列中的作业在被工作人员拾取时正在按照您的要求执行。

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

于 2011-03-04T15:29:32.947 回答