使用 Rspec 共享示例来测试 Ruby class' 属性

Use Rspec shared examples to test a Ruby class' attributes

尝试使用 Rspec 共享示例来测试两个 URL 类属性:

spec/entity_spec.rb

require 'entity'
require 'shared_examples/a_url'

describe Entity do

  # create valid subject
  subject { described_class.new(name: 'foobar') }

  context ':url attribute' do
    it_behaves_like "a URL"
  end

  context ':wikipedia_url attribute' do
    it_behaves_like "a URL"
  end

end

spec/shared_examples/a_url.rb

shared_examples_for('a URL') do |method|

    it "ensures that :#{method} does not exceed 255 characters" do
      subject.send(:method=, 'http://' + '@' * 256)
      expect(subject).to_not be_valid
    end

    it "ensures that :#{method} do not accept other schemes" do
      subject.send(:method=, 'ftp://foobar.com')
      expect(subject).to_not be_valid
    end

    it "ensures that :#{method} accepts http://" do
      subject.send(:method=, 'http://foobar.com')
      expect(subject).to be_valid
    end

    it "ensures that :#{method} accepts https://" do
      subject.send(:method=, 'https://foobar.com')
      expect(subject).to be_valid
    end

end

很明显,我需要将 :url:wikipedia_url 属性的引用发送到共享示例,但是如何?

您可以"provide context to a shared group using a block",如所述here

require "set"

RSpec.shared_examples "a collection object" do
  describe "<<" do
    it "adds objects to the end of the collection" do
      collection << 1
      collection << 2
      expect(collection.to_a).to match_array([1, 2])
    end
  end
end

RSpec.describe Array do
  it_behaves_like "a collection object" do
    let(:collection) { Array.new }
  end
end

RSpec.describe Set do
  it_behaves_like "a collection object" do
    let(:collection) { Set.new }
  end
end

您的共享示例块接受一个参数 method,但您没有将参数传递给它。然而,你们非常亲密。只需更改:

context ':url attribute' do
  it_behaves_like "a URL", :url
end

现在我们将 :url 符号作为 method 传递给共享示例。然后,您需要将对 :method= 的引用(这将失败,因为它实际上是 subject.method=)更改为 subject.send("#{method}=", value),以便我们实际上调用方法 url=。例如

it "ensures that :#{method} does not exceed 255 characters" do
  subject.send("#{method}=", 'http://' + '@' * 256)
  expect(subject).to_not be_valid
end

综上所述,我建议将局部变量的名称从 method 更改为其他名称(甚至可能 method_name),以避免混淆 method() 方法和你的局部变量 method.

Full Example