Skip to main content

Rails: RSpec, Cucumber, Authlogic, and factory_girl

After a day of work and a week of reading The RSpec Book, I got RSpec, Cucumber, Authlogic, and factory_girl to play nicely with each other. I can now test user registration, logging in, and logging out.

I can't possibly cover everything from scratch, but I'll cover some of the trickier integration points.

Setup Rails, RSpec, Cucumber, and Authlogic per their own documentation. I ended up with the following in both config/environments/test.rb and config/environments/cucumber.rb:
# There is some duplication between test.rb and cucumber.rb.
config.gem "cucumber", :lib => false, :version => ">=0.3.11"
config.gem "webrat", :lib => false, :version => ">=0.4.4"
config.gem "rspec", :lib => false, :version => ">=1.2.6"
config.gem "rspec-rails", :lib => 'spec/rails', :version => ">=1.2.6"
config.gem "thoughtbot-factory_girl", :lib => "factory_girl", :version => ">=1.2.2", :source => ""
I created a factory in test/factories/user.rb:
Factory.define :user do |u|
u.username 'john' ''
u.password 'funkypass'
u.password_confirmation 'funkypass'
u.first_name 'John'
u.last_name 'Smith'
u.billing_address "1 Cool St.\r\nBerkeley"
u.billing_state 'CA'
u.billing_zipcode '94519'
u.other_zipcode '28311' '(925) 555-1212'
I created a Cucumber feature in features/user_sessions.feature:
Feature: User Sessions

So that I can blah, blah, blah
As a registered user
I want to log in and log out

Scenario: log in
Given I am a registered user
And I am on the homepage
When I login
Then I should see "Login successful!"
And I should see "Logout"

Scenario: log out
Given I am logged in
And I am on the homepage
When I follow "Logout"
Then I should see "Logout successful!"
And I should see "Register"
And I should see "Log In
To implement this, I created step definitions in features/step_definitions/user_sessions_steps.rb
def user
@user ||= Factory :user

def login
visit path_to("the homepage")
response.should contain("Log In")
click_link "Log in"
fill_in "Username", :with => "john"
fill_in "Password", :with => "funkypass"
click_button "Login"
response.should contain("Login successful!")
response.should contain("Logout")

Given /^I am a registered user$/ do

When /^I login$/ do

Given /^I am logged in$/ do
That's it.

Authlogic's testing documentation talks about stuff like:
require "authlogic/test_case"
include Authlogic::TestCase
setup :activate_authlogic
UserSession.create(users(:whomever)) # logs a user in
In theory, you should be able to log a user in using some code--without going through the login form. I worked on this for several hours, but I wasn't able to get it to work. I googled quite a bit, but I wasn't able to find anyone else who could get this to work (i.e. integrate RSpec, Cucumber, Authlogic, and factory_girl). It seems that everyone else came to the same conclusion I did--just force the tests to use the login form.


Brandon Rhodes said…
Could you filter your posts so that Ruby-only material does not wind up on Planet Python? Thanks!
jjinux said…
See the next post.
Sarah Allen said…
so... how is the factory better than a plain old fixture?
jjinux said…
> so... how is the factory better than a plain old fixture?

1) The test data can be very near the test. 2) You can have instances inherit from each other. That way you only need to specify the things that are different and interesting. 3) You don't have a single fixtures file growing completely out of hand.
Rainer said…
>UserSession.create(users(:whomever)) # logs a user in

This didn't work for me. I used UserSession.create(:login => 'user', :password => 'password') like in the UserSessions Controller, for a normal login.
This set the current_user. Unfortunately I could use Factory Girl, because an association for the user which was created before login, did not exist after the user was logged in.
jjinux said…
As my tests are growing more and more complicated, I'm getting into situations where I don't know if I've already called Factory for a given user or not. Originally, I wrote code that would try to fetch the user from the database, and if that failed, it would call Factory. However, I found out that the object returned by Factory has a password, whereas the object returned by User.find_by_username! doesn't. Hence, I wrote the following function:

# Call "Factory user" and cache the results in the @users hash.
# user should be a symbol.
# This function serves two purposes. First of all, it prevents the same
# user from being passed to Factory twice, which would cause an error. Second
# of all, it returns the original factory object rather than looking up the
# record in the database. That's important because you can't get the password
# out of the database, and if you can't get the password out of the database,
# you can't use it to log into the site in your tests.
def user_factory(user)
user = user.to_sym # Just to be sure.
@users ||= {}
@users[user] ||= Factory user
jjinux said…
reset_session and Webrat don't play nicely with one another. See for a workaround.

Popular posts from this blog

Ubuntu 20.04 on a 2015 15" MacBook Pro

I decided to give Ubuntu 20.04 a try on my 2015 15" MacBook Pro. I didn't actually install it; I just live booted from a USB thumb drive which was enough to try out everything I wanted. In summary, it's not perfect, and issues with my camera would prevent me from switching, but given the right hardware, I think it's a really viable option. The first thing I wanted to try was what would happen if I plugged in a non-HiDPI screen given that my laptop has a HiDPI screen. Without sub-pixel scaling, whatever scale rate I picked for one screen would apply to the other. However, once I turned on sub-pixel scaling, I was able to pick different scale rates for the internal and external displays. That looked ok. I tried plugging in and unplugging multiple times, and it didn't crash. I doubt it'd work with my Thunderbolt display at work, but it worked fine for my HDMI displays at home. I even plugged it into my TV, and it stuck to the 100% scaling I picked for the othe

ERNOS: Erlang Networked Operating System

I've been reading Dreaming in Code lately, and I really like it. If you're not a dreamer, you may safely skip the rest of this post ;) In Chapter 10, "Engineers and Artists", Alan Kay, John Backus, and Jaron Lanier really got me thinking. I've also been thinking a lot about Minix 3 , Erlang , and the original Lisp machine . The ideas are beginning to synthesize into something cohesive--more than just the sum of their parts. Now, I'm sure that many of these ideas have already been envisioned within , LLVM , Microsoft's Singularity project, or in some other place that I haven't managed to discover or fully read, but I'm going to blog them anyway. Rather than wax philosophical, let me just dump out some ideas: Start with Minix 3. It's a new microkernel, and it's meant for real use, unlike the original Minix. "This new OS is extremely small, with the part that runs in kernel mode under 4000 lines of executable code.&quo

Haskell or Erlang?

I've coded in both Erlang and Haskell. Erlang is practical, efficient, and useful. It's got a wonderful niche in the distributed world, and it has some real success stories such as CouchDB and Haskell is elegant and beautiful. It's been successful in various programming language competitions. I have some experience in both, but I'm thinking it's time to really commit to learning one of them on a professional level. They both have good books out now, and it's probably time I read one of those books cover to cover. My question is which? Back in 2000, Perl had established a real niche for systems administration, CGI, and text processing. The syntax wasn't exactly beautiful (unless you're into that sort of thing), but it was popular and mature. Python hadn't really become popular, nor did it really have a strong niche (at least as far as I could see). I went with Python because of its elegance, but since then, I've coded both p