【问题标题】:How to bridge the testing using Resque with Rspec examples?如何使用 Resque 与 Rspec 示例连接测试?
【发布时间】:2011-07-05 17:03:56
【问题描述】:

在将 Resque 与 Rspec 示例并行实施时,我感到困惑。 以下是一个方法昂贵的类.generate(self) 类 SomeClass ... ChangeGenerator.generate(self) ... 结束

实现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 个单独的作业类?

【问题讨论】:

    标签: rspec resque


    【解决方案1】:

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

    • 在我们的功能测试中,我们确保作业已入队。使用 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 上,则需要使用 Monkey-patch。

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

    要在分叉的工作人员中运行作业,就像 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 工作的聪明方法。这些都是对我有用的。

    【讨论】:

    • Resque.inline = true 是一个聪明的解决方案,但正如您所指出的那样会使事情变得迟缓,而且我在一些草率的代码中遇到了一些情况,即同步运行它的结果与异步运行不同。如果 Resque 有一个测试助手,您可以在其中进行诸如 Resque.last_jobResque.process!Resque.clear! 之类的调用,那就太酷了。
    【解决方案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 方法。所以,你的工作应该有 perform 方法。

      【讨论】:

      • 关于multiple perform方法,我想我说不清楚。可以说我有 3 个工作类,每个都有一个 .perform 方法。这 3 个工作是针对同一个模型的。因此,与其编写 3 个单独的作业类,如何将这 3 个 .perform 写在一个作业类中?
      • perform 方法采用可变参数。如果您愿意,您可以添加一个鉴别器值,然后您的单个 perform 可以分派到任何提供您需要的功能的方法。
      猜你喜欢
      • 1970-01-01
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      相关资源
      最近更新 更多