ruby – RSpec – mock(或stub)覆盖mixin方法

我有这样的情况:

module Something
  def my_method
    return :some_symbol
  end
end

class MyClass
  include Something

  def my_method
    if xxx?
      :other_symbol
    else
      super
    end
  end
end

现在的问题是测试 – 我想确保从override方法调用super方法并将其存根以便我可以测试方法的其他部分.如何使用RSpec模拟实现这一目标?

解决方法

确保超级被调用听起来很像测试实现,而不是测试行为,并且模拟测试对象无论如何都不是一个好主意.我建议只是明确指定不同的代码路径

describe "#my_method" do
  it "returns :other_symbol when xxx" do
    ...
  end

  it "returns :some_symbol when not xxx" do
    ...
  end
end

如果您有很多包含该模块的类,则可以使用共享示例来减少测试中的重复.

shared_examples_for "Something#my_method" do
  it "returns :some_symbol" do
    expect(subject.my_method).to eq :some_symbol
  end
end

describe MyClass do
  describe "#my_method" do
    context "when xxx" do
      subject { ... }

      it "returns :other_symbol" do
        expect(subject.my_method).to eq :other_symbol
      end
    end

    context "when not xxx" do
      subject { ... }

      it_behaves_like "Something#my_method"
    end
  end
end

更新:如果你真的无法预测mixin的行为,你可以通过包含另一个定义它的模块来切换super调用方法.

如果你有一个包含模块M和N的C类,它们都定义了方法f,那么在C#f中,super将引用最后包含的模块.

class C
  include M
  include N

  def f
    super # calls N.f because it was included last
  end
end

如果将它包含在被测试对象的单例类中,那么它不会影响任何其他测试:

describe MyClass do
  describe "#my_method" do
    it "calls super when not xxx" do
      fake_library = Module.new do
        def my_method
          :returned_from_super
        end
      end

      subject.singleton_class.send :include,fake_library

      expect(subject.my_method).to be :returned_from_super
    end
  end
end

免责声明:这实际上并没有测试mixin的工作原理,只是super调用了.我仍然会建议实际测试行为.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...