Rails Testing: Not Just for the Paranoid
Pages: 1, 2, 3, 4, 5
What parts of my models need testing?
According to the folks who take test driven development seriously, the only features that need testing are the features that need to work. Though this is obviously a bit facetious, it's fairly close to the truth.
To break it down into a few categories, you will definitely want to test the following components of your models:
- validations
- search functions
- model logic
- anything else that does something interesting
The Entry model from Tasty has several components that fall into these categories:
app/models/entry.rb
class Entry < ActiveRecord::Base
validates_uniqueness_of :url
belongs_to :user
has_many :taggings
has_many :tags, :through => :taggings
def created_date
created_at.strftime("%Y.%m.%d")
end
def updated_date
updated_at.strftime("%Y.%m.%d")
end
# Adds a tag with the given name, if it's not already present
def tag_as(tagname)
unless tagged_as?(tagname)
tags << Tag.find_or_create_by_name(tagname)
end
end
# True if tags include a Tag with the given name, False otherwise
def tagged_as?(tagname)
tag_names.include?(tagname)
end
# returns a list of tag names
def tag_names
tags.map(&:name)
end
protected
def validate
if short_description =~ /rube goldberg/i
errors.add("short_description", "can't include references to Rube")
end
end
end
We'll start with the validation tests, and then move on to some of the other functions in this model, showing several different tests and how they work.
Testing validations
Since the purpose of a validation is to maintain data integrity, it's very important to test that they work properly. If you think about it, one intuitive way of testing a validation is to attempt saving invalid data and then to ensure it is handled correctly. That's exactly what we'll do, so let's start by ensuring our unit tests know how to fail (proving that they're hooked up). We also won't be using fixtures for this set of tests, so you can remove that line too.
test/unit/entry_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class EntryTest < Test::Unit::TestCase
def test_validates_unique_url
flunk "Test failed as expected"
end
end
If all goes well, running rake test should give you something like this:
1) Failure:
test_validates_unique_url(EntryTest) [./test/unit/entry_test.rb:5]:
Test failed as expected.
This proves that test_validates_unique_url is being called, which means we can replace it with a real test.
test/unit/entry_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class EntryTest < Test::Unit::TestCase
def test_validates_unique_url
# Add an Entry to the DB so we have something to compare against
base = Entry.create(:url => "http://rubyreports.org")
assert_valid base
e = Entry.new(:url => "http://rubyreports.org")
# entry has an identical url, so we expect it to not be valid
assert(!e.valid?, "Should not save entry unless url is unique")
assert(e.errors.invalid?(:url), "Expected an error for duplicate url")
end
end
Running the tests again, you should see that they pass. If you're paranoid, go ahead and remove the validates_uniqueness_of call from your model, and watch the tests fail.
Why no fixtures?In the User tests for Tasty, I showed how to use fixtures just because its inevitable that you'll encounter them while working with Rails. However, it turns out that they've got a few sticky spots, and a lot of times, you simply don't need them. By just explicitly calling Making ugly assertions pretty via test_helper.rbAt the very top of your test, you see that rails requires the For example, it would be nice to have an test/test_helper.rb
|



