How to pass an instance variable to an RSpec shared example

George Shaw picture George Shaw · Jul 6, 2012 · Viewed 16.4k times · Source

I'm using RSpec (2.10.1) to test validations on a model and have extracted some code to share with other model validations. The validations were first written on the Companies table, so the code looks like this:

# support/shared_examples.rb
shared_examples "a text field" do |field, fill, length|
  it "it should be long enough" do
    @company.send("#{field}=", fill * length)
    @company.should be_valid
  end

  etc...
end

and the usage is:

# company_spec.rb
describe Company do
  before { @company = Company.new( init stuff here ) }

  describe "when address2" do
    it_behaves_like "a text field", "address2", "a", Company.address2.limit
  end

  etc...
end

I'd like to pass the @company as a parameter to the shared example so I can reuse the code for different models, something like this:

# support/shared_examples.rb
shared_examples "a text field" do |model, field, fill, length|
  it "it should be long enough" do
    model.send("#{field}=", fill * length)
    model.should be_valid
  end

  etc...
end

and the usage is:

# company_spec.rb
describe Company do
  before { @company = Company.new( init stuff here ) }

  describe "when address2" do
    it_behaves_like "a text field", @company, "address2", "a", Company.address2.limit
  end

  etc...
end

However, when I do this I get undefined method 'address2' for nil:NilClass. It appears @company is not being passed (not in scope?) How do I get something like this to work?

Answer

Myron Marston picture Myron Marston · Jul 6, 2012

The problem is that self within the example group is different from self within a before hook, so it's not the same instance variable even though it has the same name.

I recommend you use let for cases like these:

# support/shared_examples.rb
shared_examples "a text field" do |field, fill, length|
  it "it should be long enough" do
    model.send("#{field}=", fill * length)
    model.should be_valid
  end
end

# company_spec.rb
describe Company do
  describe "when address2" do
    it_behaves_like "a text field", "address2", "a", Company.address2.limit do
      let(:model) { Company.new( init stuff here ) }
    end
  end
end