23

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

在子类中,我能够测试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方法的功能Childsuper我是否必须创建在提供额外参数时不调用的单独代码路径?

4

4 回答 4

21

你不能嘲笑super,你也不应该。当您模拟某些内容时,您正在验证是否收到了特定消息,而super不是消息 - 它是关键字。

相反,要弄清楚如果super调用丢失,这个类的哪些行为会改变,并编写一个练习和验证该行为的示例。

于 2013-04-07T00:44:01.587 回答
2

正如@myron 建议的那样,您可能想测试发生在super.

但如果你真的想这样做,你可以这样做:

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是弱测试的标志():

在处理遗留代码时,此功能有时很有用,但通常我们不鼓励使用它,原因有很多:

rspec-mocks API 是为单个对象实例设计的,但此功能适用于整个对象类。因此,存在一些语义上令人困惑的边缘情况。例如,在 expect_any_instance_of(Widget).to receive(:name).twice 中,不清楚特定实例是否应该接收 name 两次,或者是否预期两个接收总数。(是前者。)

使用此功能通常是一种设计气味。可能是您的测试试图做的太多,或者被测对象太复杂。

它是 rspec-mocks 中最复杂的功能,历史上收到的错误报告最多。(核心团队都没有积极使用它,这无济于事。)

于 2020-12-11T09:47:56.447 回答
2

测试这一点的一个好方法是设定超类采取的一些行动的期望 - 示例:

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

这一切都决定了在超类上调用了 Super

此模式的有用性取决于您如何构建测试/通过super所应用的方法对子/派生类的突变有什么期望。

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

YMMV

于 2016-09-28T19:59:30.207 回答
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 方法的调用。

于 2019-10-15T14:04:53.873 回答