By: Matt Lins
November 14, 2008 at 08:11 AM · Posted under BDD, Rails, factory_girl, shoulda
Is anyone else using shoulda, factory_girl and webrat for Rails integration tests?
I did a quick search and found Daniel Wellman using it in integration tests minus shoulda and factory_girl. I really like adding shoulda to get the contexts and factory_girl is a great replacement for fixtures. When combined with webrat it really makes for some easy to read integration tests. By the way, I'm already using shoulda and factory_girl for my unit and functional tests.
Here is an example I whipped up last night. It's nothing fancy. I'll probably make some modifications in the future, but so far I'm happy with it. I'm loading webrat in my test_helper.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
require '../test_helper'
class AdminLoginTest < ActionController::IntegrationTest
context 'An employee' do
setup do
@employee = Factory(:employee)
end
should 'be able to login with a valid username and password' do
visit '/admin'
assert https?
assert_equal '/admin/sessions/new', path
fills_in 'Email', :with => @employee.user.email
fills_in 'Password', :with => @employee.user.password
clicks_button 'Log In'
assert_equal @employee.user.id, session[:user_id]
end
should 'be denied access with an invalid username or password' do
visit '/admin'
assert https?
assert_equal '/admin/sessions/new', path
fills_in 'Email', :with => @employee.user.email
fills_in 'Password', :with => 'wrongpassord'
clicks_button 'Log In'
assert_nil session[:user_id]
end
end
end
|
This is testing a simple login to the admin section of a project I'm working on. We're using restful_authentication. Each line of each test is essentially an assertion. If something doesn't respond with a success or a form field is missing, the test fails.
Comments (3)
By: Matt Lins
November 11, 2008 at 12:22 PM · Posted under BDD, Rails, Ruby, factory_girl
I just ran into a problem with factory_girl sequences. The problem was I defined my Factories like this:
1
2
3
4
5
6
7
8
9
10
11
12
|
# Sequences
Factory.sequence :name do |n|
'name' + n.to_s
end
# Manufacturers
Factory.define :manufacturer do |m|
m.name Factory.next(:name)
m.active true
end
|
Assume I have a validates_uniqueness_of validation on name in Manufacturer:
1
2
3
4
5
|
class Manufacturer < ActiveRecord::Base
validates_uniqueness_of :name
end
|
Now, lets say I created a couple of manufacturers in my test setup:
1
2
3
4
5
6
7
8
9
|
require File.dirname(__FILE__) + '/../test_helper'
class ProductTest < ActiveSupport::TestCase
setup do
2.times { Factory(:manufactuer) }
end
end
|
Ok, this setup block will fail because it's creating 2 manufacturers with the same name. But, I thought I was using a sequence? Well, the sequence is only sequenced during the definition of the factories. Meaning, in the above example Factory#next was only called once.
Luckily, factory_girl allows us to use something called lazy attributes. We can just wrap our sequence with some curly brackets, like so:
|
m.name { Factory.next(:name) } |
Now everytime I create a new Manufacturer the sequence will generate a unique name. Nice! Maybe if I'd taken some more time to RTFM, I wouldn't have wasted time on this problem. Regardless, I thought maybe I'd be able to help someone else out that runs into this.
More about factory_girl
Comments (1)
By: Matt Lins
July 29, 2007 at 07:00 PM · Posted under BDD, Rails, rSpec
rSpec is all about writing easy to read, self-explanatory specs (tests to you TDDr's). It's tempting to want to use fixtures or even come up with a clever way to provide sample data for testing models. I'll demonstrate, what I consider to be the most beautiful way to write specs. Some of my influences have been the rSpec Mailing list and the PeepCode Screencast. I'll warn you brilliant ruby programmers: this is by no means efficient, DRY code. It is code that any stranger could come along and figure out exactly what the original developer was trying to accomplish.
Assume we have a simple Model like this:
1
2
3
4
5
6
|
class Post < ActiveRecord::Base
validates_presence_of :title
validates_length_of :title, :minimum => 2
end |
First we'll need the help of a couple of additional methods in Hash. Add this to your spec_helper.rb in the root of your /spec directory.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# Taken from
# http://wincent.com/knowledge-base/Fixtures_considered_harmful%3F
class Hash
# for excluding keys
def except(*exclusions)
self.reject { |key, value| exclusions.include? key.to_sym }
end
# for overriding keys
def with(overrides = {})
self.merge overrides
end
end |
These two methods with allow us to create a "valid_attributes" Hash and then tweak it later on. We're going to create a helper module at the top of the spec. This example is from one of my specs for a model: Post.
1
2
3
4
5
6
7
8
9
10
|
require File.dirname(__FILE__) + '/../spec_helper'
module PostSpecHelper
def valid_post_attributes
{
:title => "rSpec is Great"
:body => "rSpec is a fun way to write documentation
and test your application at the same time"
}
end
end |
Now we have some nice sample data. We can use this helper(don't forget to include it) in the before(setup) block of each of our describe blocks. Let start with a simple valid Post.
1
2
3
4
5
6
7
8
9
10
|
describe Post do
include PostSpecHelper
before(:each) do
@post = Post.new
@post.attributes = valid_post_attributes
end
it do
@post.should be_valid
end
end |
Great. Now let's use the add Hash#with to test one of our validations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
describe Post, "with a title that is 1 character long" do
include PostSpecHelper
before(:each) do
@post = Post.new
@post.attributes = valid_post_attributes.with(:title => "r")
end
it do
@post.should_not be_valid
end
it "should have an error on title" do
@post.should have(1).error_on(:title)
end
end |
Now, we'll use the Hash#except to test another validation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
describe Post, "with a blank title" do
include PostSpecHelper
before(:each) do
@post = Post.new
@post.attributes = valid_post_attributes.except(:title)
end
it do
@post.should_not be_valid
end
it "should have an error on title" do
@post.should have(1).error_on(:title)
end
end |
There you have it, an easy to read spec. Any developer could come along and figure out exactly what I was testing. The sample data is provided in the top of every spec. I don't have to go searching through fixtures to figure out why this test failed.
Comments (10)