Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rspec `its` syntax with dynamic conditions

Tags:

I've been really loving using contexts, subjects and its with rspec to really clean up my test code. Typical example:

context "as a user" do
  subject{ Factory :user }

  its(:name){ should == "Bob" }
end

What I can't figure out though is how I could make this condition dynamic (ie. based on other objects). its appears to instance eval the attribute within the block so I lose access to everything around it. I'd love to do something like:

its(:name){ should == subject.contact.name }

But I can't see any way of achieving this. Does anyone know if there is some a method proxied through to this instance eval that gives access to the origin object? Or if there's any other way I can use methods outside the scope of the instance of the attribute that I'm checking?

additional info

It seems as if subject within the its block gets changed to the actual attribute (name in this case)

Interestingly, I have access to any of my let methods, but again, I don't have access to my original subject in question.

like image 628
brad Avatar asked Oct 17 '11 19:10

brad


2 Answers

You are almost answering yourself, use a let assignment before you set the subject. Then you can reference it everywhere:

context "as a user" do
  let(:user) { Factory(:user) }
  subject { user }
  its(:name) { should == user.contact.name }
end

I'm a context, subject, its lover too !

like image 141
David Avatar answered Sep 22 '22 03:09

David


Not sure if there's a way to do exactly what you're asking for since the "subject" within the block becomes the return value of User#name.

Instead, I've used the let method along with the following spec style to write this kind of test:

describe User do

  describe '#name' do
    let(:contact) { Factory(:contact, name: 'Bob') }
    let(:user) { Factory(:user, contact: contact) }

    subject { user.name }

    it { should == 'Bob' }
  end

end

This of course makes some assumptions about what your contact represents (here it's an association or similar). You may also choose to stub the return value of User#contact instead of relying on FactoryGirl to set up a "real" association.

Regardless of the choices you make on those fronts, this strategy has worked well for me. I find it allows me to be more concise about what is under test, while preserving info (for other devs & future self) about where the expected return value is coming from.

like image 35
Anthony Navarre Avatar answered Sep 20 '22 03:09

Anthony Navarre