使用rspec

时间:2016-04-12 12:59:45

标签: ruby testing rspec mocking sidekiq

假设我有以下基础Ruby类:

class BaseWorker
  include Sidekiq::Worker
end

以及以下两个队列和一个助手类:

class Finder
  class << self
    def find(id)
      AwesomeDBClass.find(id)
    end
  end
end

class Queue1 extend BaseWorker
  def perform(variable)
    if variable.some_attribute
      ...
    end
  end
end

class Queue2 extend BaseWorker
  def perform id
    local_variable = Finder.find(id)
    Queue1.perform_async(local_variable)
  end
end

以下测试工具:

let(:local_variable) do
   double(:local_var, some_attribute: true)
end

let(:local_variable2) do
  OpenStruct(some_attribute: true)
end

before do
  allow(Finder).to_receive(:find).and_return(:local_variable)
  ... code that triggers queue2 ...
  queue2.drain
  queue1.drain
end

如果返回local_variable(double),则会失败:

  undefined method `some_attribute' for {"__expired"=>false, "name"=>"local_variable"}:Hash

如果返回local_variable2(openstruct),则返回:

 undefined method `some_attribute' for {"table"=>{"some_attribute"=>true}}:Hash
有趣的是,如果在queue2中检查(用puts说),那么它们的值是正确的。

另外,在阅读两个库的代码时:

https://github.com/ruby/ruby/blob/trunk/lib/ostruct.rb#L93

https://github.com/rspec/rspec-mocks/blob/31baac3ace4ec0aff97d9e4e1928b06d18c685f8/lib/rspec/mocks/test_double.rb#L10

似乎状态表明构造函数已经运行,但是其他一些东西(method_missing绑定,例如类上的其他方法定义和/或assign_stubs正在运行)没有发生。关于如何或为何如此发生的任何想法将不胜感激。

1 个答案:

答案 0 :(得分:0)

TL; DR 使用简单哈希值代替OpenStruct个实例作为perform的参数。

Sidekiq serializes Redis的所有内容,请参阅Best PracticesOpenStruct不适合作为传递给perform的参数。

次要的旁注:自Sidekiq overrides included callback起,它将更加惯用于:

class BaseWorker
  def self.extended base
    base.send :include, Sidekiq::Worker
  end
end