如何使用rspec在ruby中模拟super?

时间:2013-04-06 21:39:21

标签: ruby rspec rspec2

我通过创建一个扩展到库类的子类来扩展现有的库。

在子类中,我能够在initialize方法中测试大多数功能,但无法模拟super调用。子类看起来像下面的那样。

class Child < SomeLibrary
    def initialize(arg)
        validate_arg(arg)
        do_something
        super(arg)
    end

    def validate_arg(arg)
        # do the validation
    end

    def do_something
        @setup = true
    end
end

如何编写rspec测试(使用mocha)以便我可以模拟super调用?请注意,我正在initialize类中测试Child方法的功能。我是否必须创建单独的代码路径,在提供额外参数时不会调用super

4 个答案:

答案 0 :(得分:16)

你不能模仿super,你不应该。当您模拟某些内容时,您正在验证是否收到了特定邮件,并且super不是邮件 - 它是关键字。

相反,如果缺少super调用,请弄清楚此类的哪些行为会发生变化,并编写一个练习并验证该行为的示例。

答案 1 :(得分:1)

测试此方法的一个好方法是设置超类采取某些操作的期望 - 例如:

class Some::Thing < Some
 def instance_method
    super
 end
end

和超级班:

class Some
  def instance_method
     another_method
  end

  def self.another_method # not private!
     'does a thing'
  end
end

现在测试:

 describe '#instance_method' do 
    it 'appropriately triggers the super class method' do
      sawm = Some::Thing.new
      expect(sawm).to receive(:another_method)
      sawm.instance_method
    end
 end

所有这一切都决定了在超级类别上调用超级

这种模式的用处取决于你如何构建你的测试/你对孩子/派生类的期望&#39;通过应用super方法进行变异。

另外 - 密切关注classinstance方法,您需要相应地调整allowsexpects

YMMV

答案 2 :(得分:1)

这次聚会有点晚了,但是您也可以使用super关键字来放弃,而要做

class Parent
  def m(*args)
  end
end

class Child < Parent
  alias super_m m

  def m(*args)
    super_m(*args)
  end
end

这样,您的超级方法可以像其他任何方法一样访问,并且可以例如像其他任何方法一样被存根。主要缺点是必须将参数显式传递给对super方法的调用。

答案 3 :(得分:0)

正如@myron所建议的那样,您可能想测试超级跑车中发生的行为。

但是,如果您确实想这样做,可以这样做:

expect_any_instance_of(A).to receive(:instance_method).and_call_original

假设

class B < A
 def instance_method
    super
 end
end
class A
 def instance_method
   #
 end
end

免责声明:expect_any_instance_of是测试不力的标志。