Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an instance variable to an RSpec shared example

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?

like image 662
George Shaw Avatar asked Jul 06 '12 01:07

George Shaw


People also ask

What is shared context in RSpec?

Shared Contexts in RSpec In RSpec, every example runs in a context: data and configuration for the example to draw on, including lifecycle hooks, let and subject declarations, and helper methods. These contexts are inherited (and can be overridden) by nested example groups.

How do you set a variable in RSpec?

Another way to define a variable in RSpec is to use the let syntax. The let method should be called inside an example group. The first argument is the name of a variable to define.

What does let do in RSpec?

Use let to define a memoized helper method. The value will be cached. across multiple calls in the same example but not across examples. Note that let is lazy-evaluated: it is not evaluated until the first time. the method it defines is invoked.

What is Shared_examples?

Shared examples are a good tool to describe some complex behavior and reuse it across different parts of a spec. Things get more complicated when you have the same behavior, but it has some slight variations for different contexts.


1 Answers

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 
like image 192
Myron Marston Avatar answered Sep 20 '22 06:09

Myron Marston