【问题标题】:how to test ruby inheritance with rspec如何使用 rspec 测试 ruby​​ 继承
【发布时间】:2020-02-12 20:47:06
【问题描述】:

我正在尝试测试在类继承期间运行的逻辑,但在运行多个断言时遇到了问题。

我第一次尝试...

describe 'self.inherited' do
  before do
    class Foo
      def self.inherited klass; end
    end

    Foo.stub(:inherited)

    class Bar < Foo; end
  end

  it 'should call self.inherited' do
    # this fails if it doesn't run first
    expect(Foo).to have_received(:inherited).with Bar
  end

  it 'should do something else' do
    expect(true).to eq true
  end
end

但这失败了,因为 Bar 类已经被加载,因此没有第二次调用inherited。如果断言没有首先运行......它会失败。

然后我尝试了类似...

describe 'self.inherited once' do
  before do
    class Foo
      def self.inherited klass; end
    end

    Foo.stub(:inherited)

    class Bar < Foo; end
  end

  it 'should call self.inherited' do
    @tested ||= false
    unless @tested
      expect(Foo).to have_receive(:inherited).with Bar
      @tested = true
    end
  end

  it 'should do something else' do
    expect(true).to eq true
  end
end

因为@tested 不会在测试之间持续存在,所以测试不会只运行一次。

任何人有任何聪明的方法来做到这一点?这是一个人为的例子,我实际上不需要测试 ruby​​ 本身;)

【问题讨论】:

  • 测试行为,而不是执行。仅当方法正在执行元编程(例如构造类和设置祖先)时,测试类是否继承自来类才是合理的

标签: ruby rspec


【解决方案1】:

这是使用 RSpec 测试类继承的简单方法:

给定

class A < B; end

使用 RSpec 测试继承的更简单的方法是:

describe A do
  it { expect(described_class).to be < B }
end

【讨论】:

【解决方案2】:

对于这样的事情

class Child < Parent; end

我通常这样做:

it 'should inherit behavior from Parent' do
  expect(Child.superclass).to eq(Parent)
end

【讨论】:

    【解决方案3】:

    由于某种原因,我没有管理 solution from David Posey 工作(我想我做错了什么。请随时在 cmets 中提供解决方案)。如果有人遇到同样的问题,这也可以:

    describe A
      it { expect(described_class.superclass).to be B }
    end
    

    【讨论】:

      【解决方案4】:

      让你的类定义在测试期间运行测试继承:

      describe 'self.inherited' do
      
        before do
          class Foo
            def self.inherited klass; end
          end
          # For testing other properties of subclasses
          class Baz < Foo; end 
        end
      
        it 'should call self.inherited' do
          Foo.stub(:inherited)
          class Bar < Foo; end
          expect(Foo).to have_received(:inherited).with Bar
        end
      
        it 'should do something else' do
          expect(true).to eq true
        end
      end
      

      【讨论】:

      • 如此简单...只需为单个测试使用不同的类...当然!谢谢!
      • 我们不应该删除after回调上的类定义吗?根据课程的名称,我会说它可能有副作用。 ?Object.send(:remove_const, :Foo) 可能吗?
      • @brcebn 这里的想法是Bar 是一个只在测试中使用的一次性类。通过使用匿名类,您可以使其在多个规范示例中更加一次性和可重用,例如let(:target_class) { Class.new(Foo) }
      • 我明白你的想法。感谢您的澄清。 ?
      【解决方案5】:

      另一种方式:

      class Foo; end
      class Bar < Foo; end
      class Baz; end
      
      RSpec.describe do
        it 'is inherited' do
          expect(Bar < Foo).to eq true
        end
      
        it 'is not inherited' do
          expect(Baz < Foo).not_to eq true
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多