Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Rspec shared examples to test a Ruby class' attributes

Tags:

ruby

rspec

rspec3

Trying to use a Rspec shared example to test two URL-like properties:

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

Clearly I need to send a reference to the :url and :wikipedia_url attributes to the shared example, but how?

like image 665
craig Avatar asked Dec 08 '25 20:12

craig


2 Answers

Your shared example block takes an argument method, but you do not pass one to it. However, you are very close. Just change:

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

Now we are passing the :url symbol to the shared example as method. Then you need to change your references to :method= (which will fail because it is literally subject.method=) to subject.send("#{method}=", value) so that we are actually calling the method url=. e.g.

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

All that being said I would recommend changing the name of the local variable from method to something else (maybe even method_name) just to avoid confusion of the method() method and your local variable method.

Full Example

like image 66
engineersmnky Avatar answered Dec 10 '25 19:12

engineersmnky


You can "provide context to a shared group using a block", as described 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
like image 38
André Guimarães Sakata Avatar answered Dec 10 '25 17:12

André Guimarães Sakata



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!