abegbg
abegbg

Reputation: 191

Factory girl not initiating object

I guess the problem is that I do not know how to use factory girl with Rspec correctly. Or testing in rails correctly for that matter. Still think it is a bit weird though..

I have a class, User, with the following factory:

FactoryGirl.define do
  factory :user do
    name     "admin"
    email    "[email protected]"
    adminstatus  "1"
    password "foobar"
    password_confirmation "foobar"
  end

  factory :user_no_admin, class: User do
    name     "user"
    email    "[email protected]"
    adminstatus  "2"
    password "foobar"
    password_confirmation "foobar"
  end
...

My test looks like this:

...
describe "signin as admin user" do
  before { visit login_path }
  describe "with valid information" do
    let(:user_no_admin) { FactoryGirl.create(:user_no_admin) }
    let(:user) { FactoryGirl.create(:user) }
    before do
      fill_in "User",    with: user.name
      fill_in "Password", with: user.password
      click_button "Login"
    end

    it "should list users if user is admin" do 
      response.should have_selector('th', content: 'Name') 
      response.should have_selector('td', content: user_no_admin.name)
      response.should have_selector('td', content: user.name)
    end
  end      
end#signin as admin user
...

Basically I am trying to test that if you log in as an admin, you should see a list of all the users. I have a test for logging on as a non-admin later on in the file. I have a couple of users in the db already.

In the list of users 'admin' that logged in is displayed along with the users already in the db. 'user' is however not displayed unless I do something like this before:

fill_in "User",    with: user_no_admin.name
fill_in "Password", with: user_no_admin.password

It is as if it won't exist unless I use it. However, if I use a puts it does print the information I am putting, even if I do not do the 'fill_in' above.

I have a similar example where a puts helps me.

describe "should have company name" do
  let(:company) { FactoryGirl.create(:company) }
  let(:category) { FactoryGirl.create(:category) }
  let(:company_category) { FactoryGirl.create(:company_category, company_id: company.id, category_id: category.id) }
  it "should contain companies name" do
    puts company_category.category_id
    get 'categories/' + company.categories[0].id.to_s
    response.should have_selector('h4', :content => company.name)
  end
end

Without the puts above I get a

Called id for nil

Do I have to initiate(?) an object created by Factory girl before I can use it in some way?

Any other code needed?

Upvotes: 3

Views: 3592

Answers (4)

Bala Karthik
Bala Karthik

Reputation: 1413

Try to use trait in the factory girl,there is an example as mentioned in the this link

Upvotes: -1

user1325158
user1325158

Reputation: 234

I had a similar issue with an existing test I broke, with a slightly different cause that was interesting.

In this case, the controller under test was originally calling save, but I changed it to call save!, and updated the test accordingly.

The revised test was:

  • Declaring the instance a let statement
  • Setting an expectation on the save! method (e.g. expect_any_instance_of(MyObject).to receive(:save!) )
  • Using the instance for the first time after the expectation.

Internally, it would appear that FactoryGirl was calling the save! method, and after changing the expectation from save to save!, no work was actually done (and the code under test couldn't find the instance from the DB) that I needed to update and had a hard time getting to actually pass without a hack)

Upvotes: 1

user1170055
user1170055

Reputation: 212

Instead of:

factory :user do
  name     "admin"
  email    "[email protected]"
  ...

I will do:

factory :user do |f|
  f.name "admin"
  f.email "[email protected]"
  ...

Instead of:

let(:user_no_admin) { FactoryGirl.create(:user_no_admin) }
let(:user) { FactoryGirl.create(:user) }

I will do:

@user_no_admin = Factory(:user_no_admin)
@user = Factory(:user)

Upvotes: 1

Adrian
Adrian

Reputation: 734

let(:whatever) 

Is not creating the objects until the first time you call them. If you want it to be available before first use, use

let!(:whatever)

instead.

Or use a before block:

before(:each) do
  @company = FactoryGirl.create(:company)
  ....
end

Which will create the objects before you need to use them.

Upvotes: 9

Related Questions