In addition to the REST refactoring for SignOut, we thought we’d cover a few more changes we’d suggest.
The biggest thing which jumped out at me was that SignOut has no tests. If you’ve never written a test in rails all the different tools and frameworks available can make it seem quit daunting. It’s often hard to tell if you should you use rspec, heckle, autotest, rcov and where to start. So in this article we’ll take the set_away action from EmployeeController and write a few tests for it, using just the stuff you get for free with rails.
The action as it stands has some reasonably involved code for handling decoding time_back from the request parameters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
def set_away
@employee = Employee.find(params[:id])
if params[:date][:meridian] == "PM"
if params[:date][:hour].to_i == 12
hour = params[:date][:hour]
else
hour = (params[:date][:hour].to_i + 12).to_s
end
else
if params[:date][:hour].to_i == 12
hour = "0"
else
hour = params[:date][:hour]
end
end
time_back = Time.mktime(params[:date][:year], params[:date][:month], params[:date][:day], hour, params[:date][:minute] )
@employee.update_attributes(:reason => params[:employee][:reason], :time_out => Time.now, :time_in => time_back)
end
So there are four distinct cases that we need to ensure are tested:
A Meridian of “PM” and an hour of 12 A Meridian of “PM” and some other hour A Meridian of “AM” and an hour of 12 A Meridian of “AM” and some other hourFirst up we need some fixtures data for an employee, lets pretend I work there and create a test fixture for koz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
koz: id: 1 firstname: Michael lastname: Koziarski company_email: koz@example.com personal_email: michael@koziarski.com extension: 665 cellphone: +64 21 555 1337 homephone: +64 4 555 1337 time_out: time_in: reason: created_on: <%= 5.days.ago.to_date.to_s(:db) %> modified_on: <%= Date.today.to_s(:db) %> initials: MAK
Now the tests in EmployeeControllerTest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
class EmployeeControllerTest < Test::Unit::TestCase
def setup
@controller = EmployeeController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
# Ensure that the employees table gets reloaded as needed
fixtures :employees
# we can DRY up the test data by providing a default date
#and then just overriding what we need
def default_date
{:meridian=>"PM", :year=>now.year, :month=>now.month,
:day=>now.day, :minute=>"0", :hour=>"12"}
end
# Test the first case, PM and 12
def test_set_away_for_pm_and_12_oclock
# the default data matches this test case,
post :set_away :id=>employees(:koz).id, :date=>default_date
# ensure no errors ocurred
assert_response :success
# reload our fixture to match the database changes
koz = employees(:koz).reload
# make sure the time_back attribute has been set
assert time_back = koz.time_back
assert_equal 0, time_back.minute
# 12PM is 12 midday, so the hour should be 12
assert_equal 12, time_back.hour
# We provided a reason here, make sure the controller has set it
assert_equal "Because", koz.reason
end
end
We could continue to write tests like that, but instead we can get a little clever and let ruby write the tests for us:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
def default_date
{:meridian=>"PM", :year=>now.year, :month=>now.month,
:day=>now.day, :minute=>"0", :hour=>"12"}
end
TEST_SCENARIOS= {0=>{:hour=>"12", :meridian=>"AM"}, 5=>{:hour=>"5", :meridian=>"AM"},
18=>{:hour=>"6", :meridian=>"PM"}, 12=>{:hour=>"12", :meridian=>"PM"}}
TEST_SCENARIOS.each do |hour, hash_overide|
# Make sure we give our tests useful names, otherwise it's hard to tell what failed
name = "test_with_hour_#{hash_overide[:hour]}_and_meridian_#{hash_overide[:meridian]}"
define_method(name) do
post :set_away :id=>employees(:koz).id, :date=>default_date.merge(hash_override)
# ensure no errors ocurred
assert_response :success
# reload our fixture to match the database changes
koz = employees(:koz).reload
assert time_back = koz.time_back
assert_equal 0, time_back.minute
# Make sure the hour matches our expected hour
assert_equal hour, time_back.hour
end
end
end
Now you can refactor the set_away action without having to worry about introducing new date related bugs.
No comments yet.
You must be logged in to add your own comment.