Debugging Rails Tests with rdebug

Last updated 2009-09-15.

Let's take a contrived & hypothetical example that's easy to follow. I have a method which is supposed to add two numbers and return the result, or 10, whichever is higher. But when I run it ...

duncan@duncan-desktop:~/demo$ rake test:units
(in /home/duncan/demo)
/usr/bin/ruby1.8 -Ilib:test "/usr/lib/ruby/1.8/rake/rake_test_loader.rb" "test/unit/calculator_test.rb"
Loaded suite /usr/lib/ruby/1.8/rake/rake_test_loader
Started
F
Finished in 0.027942 seconds.

1) Failure:
test_add_to_max_of_ten_limits_to_ten(CalculatorTest)
[./test/unit/calculator_test.rb:6:in `test_add_to_max_of_ten_limits_to_ten'
/home/duncan/demo/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/testing/default.rb:7:in `run']:
<10> expected but was
<11>.

1 tests, 1 assertions, 1 failures, 0 errors
rake aborted!
Command failed with status (1): [/usr/bin/ruby1.8 -Ilib:test "/usr/lib/ruby...]

(See full trace by running task with --trace)

The first thing I need to do is install the ruby-debug gem:

duncan@duncan-desktop:~/demo$ sudo gem install ruby-debug
Successfully installed ruby-debug-0.10.1
Installing ri documentation for ruby-debug-0.10.1...
Installing RDoc documentation for ruby-debug-0.10.1...

... and then test that it's been installed:

duncan@duncan-desktop:~/demo$ rdebug --version
ruby-debug 0.10.1

If you see an error like rdebug: command not found then you'll need to add your gem bin directory to your PATH. On Xubuntu I added the following line to ~/.bashrc:

export PATH=$PATH:/var/lib/gems/1.8/bin

Back to the code; now I can add a breakpoint to the calculator model. To add an rdebug breakpoint all I need to do is call debugger; in this case I'll make it conditional upon the two parameters totalling to more than 10:

class Calculator < ActiveRecord::Base

def self.add_to_a_max_of_ten(a, b)
result = 0
debugger if a + b > 10
if result > 10
result = 10
end
result = a + b
return result
end

end

Then I run the test through rdebug:

duncan@duncan-desktop:~/demo$ rdebug test/unit/calculator_test.rb
test/unit/calculator_test.rb:1
require File.dirname(__FILE__) + '/../test_helper'
(rdb:1)

The debugger breaks automatically at the start of the test; I can make it continue easily enough:

(rdb:1) continue
Loaded suite test/unit/calculator_test
Started
/home/duncan/demo/app/models/calculator.rb:6
if result > 10

Right, now I'm at the point where I can start examining the program flow and figuring out why it's failing. Firstly, what's the value of result at this point?

(rdb:1) var local
a => 5
b => 6
result => 0

Ohhhh, right. That might be the problem. So, where am I again in the source? I can take a look at the source with the list command:

(rdb:1) list =
[1, 10] in /home/duncan/demo/app/models/calculator.rb
1 class Calculator < ActiveRecord::Base
2
3 def self.add_to_a_max_of_ten(a, b)
4 result = 0
5 debugger if a + b > 10
=> 6 if result > 10
7 result = 10
8 end
9 result = a + b
10 return result

At this point, I can see what's going to happen - the interpreter will skip to line 9, perform the addition, and return whatever the result is. But being the cynical soul that I am (when it comes to anything electronic) I can verify this by stepping over the next few lines, and verify the result before it's returned:

(rdb:1) next
/home/duncan/demo/app/models/calculator.rb:9
result = a + b
(rdb:1) next
/home/duncan/demo/app/models/calculator.rb:10
return result
(rdb:1) var local
a => 5
b => 6
result => 11

So now, I can go on to fix the method, and verify the fix by observing that the test passes.