Firstly, this question may stray into opinion but I think it's a valuable question to ask. I will give a very specific example for my application which handles absence management and tracking.
An Account
has many Users
and a User
has many Absences
. The Account
can create PublicHolidays
which should be ignored when calculating the number of days that an Absence
uses.
Example: If a person takes a week off, the days used will be 5. If one of those days is a PublicHoliday
, the days used would be 4.
I want to implement a method such that when a PublicHoliday
is created, the days used for any Absences
created prior to the date of creation and which cross the date of the PublicHoliday
are recalculated.
My current RSpec test looks like this:
it 'triggers a recalculation of absence days on create for absences created before the date of creation of the public holiday' do
robin = FactoryGirl.create(:robin)
absence = FactoryGirl.create(:basic_absence, user: robin)
expect(absence.days_used).to eq(1)
ph = FactoryGirl.create(:public_holiday, country: "England", account: robin.account)
expect(absence.reload.days_used).to eq(0)
end
In this test, ph
is the same date as the absence
so I expect it to calculate one day to start with and then I intend to use an after create callback to recalculate the days used.
Is this the right way to do this test? Is there a more efficient way without creating a number of associated objects?
Firstly - it's good practice to use let
s instead of local variables, and secondly - split your tests so each test tests just one thing. Thirdly: anything that sets up a context for tests should be put into a context-block (even if there's only one test in that context)
eg, here's a re-writing of your spec the standard way:
let(:robin) { FactoryGirl.create(:robin) }
let(:absence) { FactoryGirl.create(:basic_absence, user: robin) }
context "with no public holidays" do
it 'counts the absence day to be a day used' do
expect(absence.days_used).to eq(1)
end
end
context "with a public holiday for the absence" do
before do
FactoryGirl.create(:public_holiday, country: "England", account: robin.account)
end
it 'does not consider the absence day to be a day used' do
expect(absence.days_used).to eq(0)
end
end