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:

  1. Log into the application.
  2. Change your date format to dd/mm/yy
  3. 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.

More articles in this series