Testing a Little More
Too often we treat testing as an all or nothing activity. If you aren’t in the habit of writing tests, or just find it frustrating, then it feels like a lost cause.
One of the best ways to add useful tests to your application is to write one each time you fix a bug. These tests cover real world problems, and verify when the issue is fixed.
Let’s work through an example to see how this might play out.
The Bug
You rolled out a new feature yesterday, and all seemed fine, but in the middle of the night a number of bug reports started drifting in. Here’s an example:
When I entered 25/12/15 as the deadline for my project, your website crashed. I don’t think it’s supposed to do that. Can you fix this?
— Rather Civil User
Luckily, this includes most of the information you need to solve the problem.
After a little poking around, you realize the user was using the dd/mm/yy
date format. If you change your date format, you can no longer enter deadlines. This is perfect! You’ve found a way to reproduce the bug. The steps are:
- Log into the application.
- Change your date format to
dd/mm/yy
- Enter
25/12/15
as the deadline for a project
The Test
We can write a test that follows the steps we outlined above:
test "Users with dd/mm/yy date format should be able to enter deadlines" do
# Get a project
project = Project.create!
# Change user's date format:
user = users(:active_user)
user.preferences.date_format = "%d/%m/%y"
user.save!
# Sign in
sign_in user
# Update
post :update, id: project_id, project: { deadline: "25/12/15" }
project.reload
assert_equal Date.new(2015,12,25), project.deadline
end
Running the test causes an exception: ArgumentError: invalid date
. This is great, we have a failing test that corresponds with the steps we followed to reproduce the user’s bug. Now we’re ready to fix the bug.
The Fix
The argument error was coming from Date.strptime
. Instead of using the user’s date format, the code assumed mm/dd/yy
. Make the change, run your tests, and everything passes. We test it manually for good measure, and see that entering deadlines works.
Now we have a fix, and a test that documents a piece of behavior we forgot to implement.
The Real World
Of course bugs are rarely this convenient. If the bug reports are unclear, you may miss the root cause, or include several unnecessary steps. Before you’re done, update the test to illustrate your fix as clearly as possible. In the example above we should change the name of the test to explain the expected behavior:
test "Deadlines are parsed with the user's date format" do
#...
end
Now when the next developer views this test, its intent will be more clear.
TDD
I’m going to let you in on a little secret. We just did a bit of pragmatic TDD (Test Driven Development). It doesn’t have to be an all or nothing practice, and it certainly doesn’t need to be hard. Writing tests while fixing bugs is a great way to start testing a little more.