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?
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With