Replacing mock objects with factory girl in controller rspecs

Problem

You would like to use factory_girl instead of the mock models described in the RSpec book (Behaviour Driven Rails – Rails Controllers – Controller specs).

 

Solution

Make sure that you use let! instead of let and have the following:

 

require 'spec_helper'

describe MessagesController do
  describe "POST create" do
    let!(:message) { Factory.create(:message) }
    
    before do 
      Message.stub(:new).and_return(message)
    end
    
    it "creates a new message" do
      Messagee.should_receive(:new).with("text" => "a quick brown fox").and_return(message)
      post :create, :message => {"text" => "a quick brown fox"}
    end
    
    it "saves the message" do
      message.should_receive(:save)
      post :create
    end

    it "redirects to the Messages index" do
      post :create
      response.should redirect_to(:action => "index")
    end
  end
end

Cucumber Table transformations with Factory Girl

Problem
After reading this post here, to be able to use the Cucumber table trasformatios feature to build objects in your cucumber tests, you would like to use FactoryGirl instead of the standard model.
The reason for using FactoryGirl could be that your model needs a few more attributes (mandatory fields), that you don’t want to specify in your cucumber table, but you want the factory to take care of them.

Solution
The only difference would take place in the transformation step.
So if you would originally have the following:

Transform /^table:Vehicle,User,Start,End$/ do |table|
  table.hashes.map do |hash|
    vehicle = Vehicle.create!({:regno => hash['Vehicle']})
    user = User.create!({:first_name => hash['User']})
    booking = Booking.create!({:start_at => hash['Start'],
                               :end_at => hash['End']})
    {:vehicle => vehicle, :user => user, :booking => booking}
  end
end

and for example your user has also fields like password, date of birth, that are mandatory in the model validations, you would put them in your factory define declaration like:

Factory.define(:user) do |u|
u.first_name "Name"
u.last_name "Lastname"
u.address1 "Address1"
u.address2 "Line 2"
u.address3 "Line 3"
u.zip "1111"
u.city "City"
u.sequence(:email) {|n|"teste#{n}@test.com"}
u.profile_picture File.open(File.join(Rails.root,"features/fixtures/user.png"))
u.password "password"
end

and replace the tranformation to:

 

Transform /^table:Vehicle,User,Start,End$/ do |table|
table.hashes.map do |hash|
vehicle = Factory(:vehicle, :regno => hash['Vehicle'])
user = Factory(:user,:first_name => hash['User'])
booking = Factory(:booking, :start_at => hash['Start'],
:end_at => hash['End'])

{:vehicle => vehicle, :user => user, :booking => booking}
end
end

The actual step would similar to the one in the blog article:

Given /^the following bookings?:$/ do |table|
# table is a Cucumber::Ast::Table
table.each do |group|
booking = group[:booking]
associations = {:vehicle => group[:vehicle], :user => group[:user]}
booking.update_attributes(associations)
end
end

You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.

Problem
You would like to use Carrierwave for file uploads, but you get the following error if you are trying to use factories for running your cucumber scripts:

You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.

That happens if you try to assign inside your factory template, to your file field the path like f.file “path_to_file”

Solution

You would need to slightly modify your factory template to use the file path as follows:

f.file File.open(File.join(Rails.root,"path_to_file"))

Using factory_girl Factory in test console

Problem
You would like to test your factory_girl factories in the rails test console, but you get an error when you try to use an existing factory.

Solution

  1. Start your console in the test evnivornment:
    rails c test
  2. require your factories.rb file in the console:
    require 'absolute_path/to/your/factories.rb'
  3. you should be able to use your factory now :
    t=Factory.create(:existing_factory_name)

NameError: uninitialized constant UserTest::Factory

Problem
You are trying to use shoulda with factory_girl but you are getting the above error:

NameError: uninitialized constant UserTest::Factory

Solution
Insert the following to your config/environments/test.rb
config.gem 'shoulda', :lib => 'shoulda'

install the gem with:
sudo gem install shoulda

add the following to your test/test_helper.rb
require 'factory_girl'
require "factories"

in your test use the new syntax without the underscore, as in:
should belong_to(:model)