如何在 RSpec 中包含模块/测试接口/测试角色?将 POODR 测试代码从 Minitest 转换为 RSpec

Ray*_*Gan 5 rspec module minitest

我想将 Sandi Metz 在“POODR”中的最终测试代码从 Minitest 翻译为 RSpec。在第 9 章中,她检查“包含 DiameterizedInterfaceTest”的任何对象是否具有“diameter”方法。在这里,它检查 DiameterDouble 和 Wheel 是否都有“直径”方法:

module DiameterizableInterfaceTest
  def test_implements_the_diameterizable_interface
    assert_respond_to(@object, :diameter)
  end
end

class DiameterDouble
  def diameter
    10
  end
end

class DiameterDoubleTest < MiniTest::Test
  include DiameterizableInterfaceTest

  def setup
    @object = DiameterDouble.new
  end
end

class WheelTest < MiniTest::Test
  include DiameterizableInterfaceTest

  def setup
    @wheel = @object = Wheel.new(26, 1.5)
  end

  def test_calculates_diameter
    assert_in_delta(29,
                    @wheel.diameter,
                    0.01)
  end
end
Run Code Online (Sandbox Code Playgroud)

这有效。就这 1 行“include DiameterizableInterfaceTest”就可以了。但是,我不能在 RSpec 中做同样的事情。我试过:

module DiameterizableInterfaceTest
  describe 'object has diameter method' do
    it 'implements diameterizable interface' do
      expect(object).to respond_to(:diameter)
    end
  end
end

class DiameterDouble
  def diameter
    10
  end
end

describe DiameterDouble do
  include DiameterizableInterfaceTest
  let (:object) { DiameterDouble.new }
end
Run Code Online (Sandbox Code Playgroud)

但是模块中“对象”的所有组合都会失败。如果我使用“对象”,它会显示“未定义的局部变量或方法‘对象’”。对于“@object”,它表示“预计对 :diameter 的响应为零”。对于“:object”,它表示“预期:object 响应:diameter”。

要将该模块包含在 RSpec 中,唯一有效的方法是将“描述”块更改为方法,如下所示。这迫使我为“has_diameter_method?”添加一个 it-block。对于我检查的每一堂课,这都是荒谬而冗长的:

module DiameterizableInterfaceTest
  def has_diameter_method?
    expect(@object).to respond_to(:diameter)
  end
end

class DiameterDouble
  def diameter
    10
  end
end

describe DiameterDouble do
  include DiameterizableInterfaceTest
  before do
    @object = DiameterDouble.new
  end

  it 'has diameter method' do
    has_diameter_method?
  end
end

describe Wheel do
  include DiameterizableInterfaceTest

  describe '#diameter' do
    before do
      @wheel = @object = Wheel.new(26, 1.5)
    end
    it 'calculates diameter' do
      expect(@wheel.diameter).to eq(29)
    end

    it 'has diameter method' do
      has_diameter_method?
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

如何在 RSpec 的多个类测试中包含模块,就像我在 Minitest 中所做的那样,而不添加这个额外的 it-block?在 Minitest 中,我可以使用 1 行“include DiameterizedInterfaceTest”为每个类添加此检查。在 RSpec 中,还需要 4 行。

这是我想做的另一个例子。在 Minitest 中很容易,但在 RSpec 中则不然。

Ray*_*Gan 5

我找到答案了!谢谢你,CodeSchool:http://rspec.codeschool.com/levels/4/challenges/4

我的 RSpec 解决方案:https://github.com/rayning0/poodr/blob/master/spec/ch9g_spec.rb

关键是使用shared_examples,它允许通用对象(“it”)。在测试中,我用来it_behaves_like检查shared_examples中的所有行为。另外,对于 Wheel,我需要添加subject { wheel },或者它会说ArgumentError: wrong number of arguments (0 for 2)

shared_examples 'Diameterizable' do
  it { should respond_to(:diameter) }
end

class DiameterDouble
  def diameter
    10
  end
end

describe DiameterDouble do
  it_behaves_like 'Diameterizable'
  let(:object) { DiameterDouble.new }
end

describe Wheel do
  it_behaves_like 'Diameterizable'
  let(:wheel) { Wheel.new(26, 1.5) }
  subject { wheel }

  it 'calculates diameter' do
    expect(wheel.diameter).to eq(29)
  end
end
Run Code Online (Sandbox Code Playgroud)