This post is an overview of how I am using Rails3, rspec, and factory_girl to test my ActiveRecord models. Its not a complete or thorough tutorial, though I think I’ve covered most of the components and included some thoughts on the matter. It should serve its purpose, if not, ask your questions via the comment form.
I am working on another Rails 3 app. This one is a well defined app - its something I’d built in PHP before, and now I’m rebuilding in Rails 3. As such, I have a good idea of everything it should do.
Yes, this is the perfect scenario for using specification tests with RSpec.
Instead of fixtures, I’m using factories, more specifically, factory_girl.
What is Factory Girl?
Factory Girl (factory_girl) is a gem that can be used to create objects. The process is quite similar to using fixtures, though the format and syntax is different.
Examples help, so here we go! A quick overview:
The app I am building is a DNS management tool. The base models are "zone" and "record". The zone model is the origin part of a zonefile, and includes a field named origin. For a single DNS server, the origin must be unique.
The Zone Model
Here is the zone model, including a couple, but not all, validations:
class Zone < ActiveRecord::Base
validates :origin,
:presence => true,
:uniqueness => true
validates :ttl,
:numericality => true
end
The Zone Factory
Here is the zone factory, located in spec/support/zone.rb:
Factory.define :zone, :class => Zone do |f| f.id 1 f.origin 'example.com.' f.ttl 14400 f.mbox 'support@example.com' f.ns 'ns.example.net' end
Note: this is really what I like about factories - they feel a lot more like Ruby than YAML.
The Model Test
Here is the zone model spec test, which was initially auto-generated by rails, and of course actually written by yours truly:
require 'spec_helper'
describe Zone do
before(:all) do
@zone = Factory.build(:zone)
@zone.save
end
it "should be able to create a new zone" do
puts @zone.errors.inspect
@zone.should be_valid
end
it "should require origin to be unique" do
zone = Zone.new(:id => 2, :origin => 'example.com.')
zone.save
zone.should_not be_valid
zone.errors[:origin].should == ["has already been taken"]
end
it "should not update with invalid data" do
@zone.update_attributes({:ttl => 'kasjdfkhd'})
@zone.should_not be_valid
end
after(:all) do
@zone.delete
end
end
I run these tests with: rake spec.
I hope this quick overview helps - I’m off to write more model tests. :-)
