anti-k
anti-k

Reputation: 317

How to set a shared example?

I'm just learning to write specs in ruby, and rails. So I do have two similar models that act similar when voted: question and answer. So I try to not duplicate code and write shared example for this two.

RSpec.shared_examples_for 'User Votable' do

  let!(:user){ create :user } 
  let!(:sample_user){ create :user }   
  let!(:vote){ create :vote, user: user, votable: votable, vote_field: 1}   

  it 'user different from resource user is accapteble' do        
    expect(votable.user_voted?(sample_user)).to be_falsy
  end   

  it 'user similar to resource user is accapteble' do

    expect(votable.user_voted?(user)).to be_truthy
  end

end

And a test itself

describe 'user_voted?' do 
  def votable
    subject{ build(:question)}
  end
  it_behaves_like 'User Votable'
end

The last it in this spec fails( I think because of subject - it does not change when I create a vote) So I would be very happy if I could manage and understand how to do it right way. And very thankful for any advice

Also when I try to use mock like this, it complains on not having primary key

allow(:question){create :question}

Failures:

1) Question user_voted? behaves like User Votable user similar to resource user is accapteble Failure/Error: expect(votable.user_voted?(user)).to be_truthy

   expected: truthy value
        got: false
 Shared Example Group: "User Votable" called from ./spec/models/question_spec.rb:23

Upvotes: 0

Views: 99

Answers (2)

Chris Salzberg
Chris Salzberg

Reputation: 27374

You actually don't need to use subject, you can just set whatever context you want using let and it will be available within the block:

describe 'user_voted?' do 
  let(:votable) { build(:question) }
  it_behaves_like 'User Votable'
end

Then you can just refer to votable within your shared example and it will be defined by the context:

RSpec.shared_examples_for 'User Votable' do
  let!(:user) { create :user } 
  let!(:sample_user) { create :user }   
  let!(:vote) { create :vote, user: user, votable: votable, vote_field: 1 }

  it 'user different from resource user is acceptable' do        
    expect(votable.user_voted?(sample_user)).to be_falsy
  end   

  it 'user similar to resource user is acceptable' do
    expect(votable.user_voted?(user)).to be_truthy
  end
end

You can also incidentally pass parameters into the it_behaves_like block for more flexibility.

Ref: Providing context to a shared group using a block

(Note: fixed some spelling typos above.)

Upvotes: 1

Kris
Kris

Reputation: 19938

Instead of having a votable method could you set the subject as such:

it_behaves_like 'User Votable' do
  subject { build(:question) }
end

Upvotes: 1

Related Questions