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

Aut*_*act 23 rspec resque

与Rspec示例并行实现Resque时,我感到困惑.以下是一个类昂贵的方法.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
Run Code Online (Sandbox Code Playgroud)

它完美地运作.但我有两个问题.

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

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

nir*_*rum 34

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

  • 在我们的功能测试中,我们确保作业入队.使用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工作的聪明方法.这些都是为我工作的.

  • `Resque.inline = true`是一个聪明的解决方案,但正如你所指出的那样可以让事情变得迟钝而且我在一些草率的代码中遇到了案例,其中同步运行它的结果与异步运行不同.如果Resque有一个测试帮助器,你可以做一些调用,比如`Resque.last_job`,`Resque.process!`和`Resque.clear!`,那会很酷. (3认同)

小智 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
Run Code Online (Sandbox Code Playgroud)

并为您的集成测试:

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
Run Code Online (Sandbox Code Playgroud)