TDD and Debugging in Ruby/Rails?
Developing a Ruby/Rails application TDD style, and then in the middle of your spec something odd happens: Wouldn’t it be nice to fire up the debugger exactly in that spot? Here is how I am doing this right now, while using Rails, rspec and guard. Well, and pry, which in itself is worth checking out.
Let’s say I have the following spec:
describe User do it "does not allow the same user name again" do user = User.create(first_name: 'Tom', last_name: 'Sawyer') User.create(first_name: 'Tom', last_name: 'Sawyer').should have(1).error_on(:first_name) end end
The test fails as follows, but why? I’ve just added the appropriate uniqueness constraint in the User model, so what’s going wrong?
1) User does not allow the same user name again Failure/Error: User.create(first_name: 'Tom', last_name: 'Sawyer').should have(1).error_on(:first_name) expected 1 error on :first_name, got 0 # ./spec/models/user_spec.rb:6:in `block (2 levels) in (required)>'
Something odd might be happening, so I call pry to the rescue by adding two lines into the test:
describe User do it "does not allow the same user name again" do user = User.create(first_name: 'Tom', last_name: 'Sawyer') require 'pry' binding.pry User.create(first_name: 'Tom', last_name: 'Sawyer').should have(1).error_on(:first_name) end end
Guard re-runs the test and stops with a REPL. A quick debug session (reproduced below) reveals what the issue is:
Running: spec/models/user_spec.rb From: /Users/chris/Documents/odr/spec/models/user_spec.rb @ line 7 in RSpec::Core::ExampleGroup::Nested_2#N/A: 2: 3: describe User do 4: it "does not allow the same user name again" do 5: user = User.create(first_name: 'Tom', last_name: 'Sawyer') 6: require 'pry' => 7: binding.pry 8: User.create(first_name: 'Tom', last_name: 'Sawyer').should have(1).error_on(:first_name) 9: end 10: end pry(#)> User.count => 0 pry(#)> user.errors => #, @messages={:email=>["can't be blank"], :password=>["can't be blank"]}> pry(#)>
Aha, the first user didn’t even get created! I better provide values for email and password. A quick change to the spec makes guard run it again, this time it succeeds:
describe User do it "does not allow the same user name again" do user = User.create(first_name: 'Tom', last_name: 'Sawyer', email: 'tom@twain.com', password: 'secret') User.create(first_name: 'Tom', last_name: 'Sawyer', email: 'tom@gmail.com', password: 'whateva').should have(1).error_on(:first_name) end end
Note: I didn’t use anything to facilitate sample data for this test. In order to stay sane using factory_girl or fixtures is the way to go. Ryan Bates has created an excellent 15 minute intro on how he does all that.





