【问题标题】:Mocking a dynamically-generated class in ruby metaprogramming with rspec使用 rspec 在 ruby​​ 元编程中模拟动态生成的类
【发布时间】:2011-11-29 10:52:37
【问题描述】:

我是 TDD 元编程的新手,所以请耐心等待!

我有一个 Reporter 类(用于包装 Garb ruby​​ gem),当我点击 method_missing 时,它将即时生成一个新的报告类并将其分配给 GoogleAnalyticsReport 模块。主要要点如下:

# Reporter.rb 
def initialize(profile)
  @profile = profile
end

def method_missing(method, *args)       
  method_name = method.to_s
  super unless valid_method_name?(method_name)

  class_name = build_class_name(method_name)
  klass = existing_report_class(class_name) || 
    build_new_report_class(method_name, class_name)
  klass.results(@profile)
end

def build_new_report_class(method_name, class_name)
  klass = GoogleAnalyticsReports.const_set(class_name, Class.new)
  klass.extend Garb::Model
  klass.metrics << metrics(method_name)
  klass.dimensions << dimensions(method_name)
  return klass
end

Reporter 期望的“配置文件”类型是 Garb::Management::Profile。

为了在这个 Reporter 类上测试我的一些私有方法(例如 valid_method_name? 或 build_class_name),我想我想用 rspec 模拟配置文件,因为这不是我感兴趣的细节。

但是,对 klass.results(@profile) 的调用 - 正在执行并杀死我,所以我没有对我在元部分中扩展的 Garb::Model 进行存根。

到目前为止,我是这样模拟和存根的……规范的实现当然不重要:

describe GoogleAnalyticsReports::Reporter do
  before do
    @mock_model = mock('Garb::Model')
    @mock_model.stub(:results) # doesn't work!

    @mock_profile = mock('Garb::Management::Profile')
    @mock_profile.stub!(:session)

    @reporter = GoogleAnalyticsReports::Reporter.new(@mock_profile)
  end

  describe 'valid_method_name' do
    it 'should not allow bla' do
      @reporter.valid_method_name?('bla').should be_false
    end
  end
end

有谁知道我如何在我新创建的类上对 results 方法的调用存根?

任何指针将不胜感激!

~斯图

【问题讨论】:

    标签: ruby rspec mocking metaprogramming


    【解决方案1】:

    代替:

    @mock_model = mock('Garb::Model')
    @mock_model.stub(:results) # doesn't work!
    

    我想你想做:

    Garb::Model.any_instance.stub(:results)
    

    这将剔除任何 Garb::Model 实例以返回结果。您需要这样做,因为您实际上并没有将 @mock_model 传递给任何将使用它的类/方法,因此您必须更加通用。

    【讨论】:

    • 我的项目是 rails 2.3,所以在升级 rspec 模拟时,我不得不将我的课程拉出到一个新的 gem 中,以释放 web pf 依赖项。我仍然有一个问题......我们正在尝试对 Garb::Model 的任何实例进行存根,它实际上是一个模块,而不是一个类。 Rspec 给我:失败/错误:Garb::Model.any_instance.stub(:results) NoMethodError: undefined method `any_instance' for Garb::Model:Module 任何想法如何模拟扩展模块的类的任何实例?干杯
    • 我认为您需要 rspec 2.6 或更高版本才能获得 any_instance 支持。据我所知,就存根模块而言,这是不可能的——除了在模块的 eingen 类上定义方法(def self.hello_world)。如果您不知道要存根的实例,那么我认为您的测试可能走错路了..
    • 同意 Derek - 我想我很纠结,因为我的代码不够正确(阅读:可测试)。感谢您的回答。对于任何阅读和感兴趣的人,我最终使用 VCR 和 fakeweb 来删除 Garb 所需的 http 内容。在这里查看我的实现:github.com/stuliston/garb-reporter/blob/master/spec/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多