Latest Notebook Article
Getting started with automated testing in Rails
Published 3 days ago by Justin French
After my previous post learn to test your code, you might be wondering how to get started with automated testing. Many books have been written on the topic, but I thought it might be interesting to share how I got started.
Testing in the Rails console
One of my favorite things about Rails is the console (a Ruby irb console with the Rails environment loaded into it). If you haven’t checked it out yet, go have a play. You have access to ruby, your models, the database, helpers, ActiveSupport and much more. Here’s a quick example:
$ ./script/console
Loading development environment (Rails 2.3.4)
>> "Hello World!".class
=> String
>> Post.count
=> 100
>> Post.published.last.title
=> "Hello world!"
I found I was playing around in console quite a lot when testing specific logic in my models, like validations. It was far easier to copy-and-paste a few lines of ruby over and over instead of clicking around in my browser and entering data in all those form fields.
Let’s say you want to confirm that a new Post is valid when given an expected hash attributes (that the browser would usually post from a form being submitted):
>> Post.new.valid?
=> false
>> Post.new(:title => "Hello", :body => "World", :user_id => "1").valid?
=> true
While the example may be trivial, that’s actually the point. The tests I was performing in the console were exactly what I should have been automating — small, isolated, repeatable chunks of Ruby that confirm my understanding of what the code does by using it in the same way that I intended it to be used in my application.
In this case, I’m simply confirming that a new Post without attributes is invalid, and that a new Post with a title, body and user_id is valid.
A quick introduction to unit tests
For simplicity, I’m going to stick with test/unit and whatever ships with Rails in the standard testing framework provided in Rails 2.3.x, but you should be able to adapt these to rspec, Rails 3 or whatever you like.
If you used a generator to create your Post model in the first place, you should already have a file ready for your tests, located in RAILS_ROOT/test/unit/post_test.rb:
require 'test_helper'
class PostTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end
You should be able to run your unit tests from the command line with this rake task:
$ rake test:units
A bunch of noise is printed onto the screen, but what you’re looking for is something like this:
Started
.
Finished in 0.12 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
My friends, that dot is a passing test. Let’s add a failing test, to check everything is working as expected:
require 'test_helper'
class PostTest < ActiveSupport::TestCase
test "the truth" do
assert true
end
test "cats are the same as dogs" do
assert_equal "cats", "dogs"
end
end
Run the tests, we should see a failure:
Started
.F
Finished in 0.12 seconds.
2 tests, 2 assertions, 1 failures, 0 errors
1) Failure:
test_cats_are_the_same_as_dogs(PostTest)
[/test/unit/post_test.rb:9]:
<"cats"> expected but was
<"dogs">.
Finally, automating our tests
Let’s take a look at our console tests again:
>> Post.new.valid?
=> false
>> Post.new(:title => "Hello", :body => "World", :user_id => "1").valid?
=> true
The automated unit tests for these two are dead simple:
test "should be invalid with no attributes" do
assert !Post.new.valid?
end
test "should be valid with a title, body and user_id" do
assert Post.new(:title => "Hello", :body => "World", :user_id => "1").valid?
end
Run the tests, let’s see the dots!
Started
..
Finished in 0.12 seconds.
2 tests, 2 assertions, 0 failures, 0 errors
Despite being utterly simple and trivial, those two tests document my understanding of what the software does (and should do going forward):
- A Post with no attributes should be invalid.
- A Post with a title, body and user_id should be valid.
When they fail, either code isn’t doing what I expect, or the test is no longer valid. I’ll adjust one of them accordingly.
And that’s how I got started
What about you? It’ll be tempting to open every model, look at every line of code and write tests for everything. That’s an incredibly ambitious plan, especially while you’re learning how to write good tests, how to structure them, etc.
Instead, start with one of your most business-critical controllers. Maybe it’s the signup process, or the home page, or the checkout. Have a look at how you’re using your models, and replicate that usage with automated tests. Start with the golden path, then add more tests for the edge cases and irregular parts.
Another way to proceed is to start by writing a test to expose any bugs you come across. Write a failing test, fix the bug, watch the test pass, commit the changes.
I’ll cover both of these (and much more) soon.
Previous Notebook Articles
Learn how to test your code
Published 16 days ago by Justin French
Moving to Feedburner, please update your feed URL
Published 17 days ago by Justin French
Nested has_many :through associations in Rails
Published 35 days ago by Justin French
Google and IE6: Put the Champagne Away
Published 37 days ago by Justin French