My Rails models: task has_many positions.
Scenario: When I create a new position, it should create itself a task. I’d like to test that, and I’m doing it like this:
context "creating a new position" do
let(:position) { create :position, name: 'Read some books', :task => nil }
it "should create a simple task" do
Task.find_by_name('Read some books').should be_nil # First should
position # Execute let() block (FactoryGirl is lazy evaluating)
Task.find_by_name('Read some books').should_not be_nil # Second (more relevant) should
end
end
So how should I improve my test? The first “should” simply makes sure that there isn’t already a Task, so we can be sure that creating the Position creates the Task. But this violates the “only one should per it block” principle. So what about this?
context "creating a new position" do
let(:position) do
position = create :position, name: 'Read some books', :task => nil
Task.delete_all
position
end
it "should create a simple task" do
position # Execute let() block (FactoryGirl is lazy evaluating)
Task.find_by_name('Read some books').should_not be_nil
end
end
Or should I simply count on the fact that there shouldn’t be such a task anyways (because a clean test db wouldn’t have one)? Thanks for your opinions.
Update (Solution)
After some research I found the change matcher of RSpec:
let(:position) { create :position, name: 'Read some books', :task => nil }
it "should create a simple task" do
# Thanks to FactoryGirl's lazy evaluation of let(), the position doesn't yet exist in the first place, and then after calling position in the expect{} block, it is created.
expect { position }.to change{ Task.count(conditions: { name: 'Read some books' }) }.by(1)
end
RSpec 2.11 allows you to pass a block to
change, and it expects the return value of the block to be the thing that changes. I would expect this to work for you: