5
votes

I am using Rspec with selenium-webdriver gem to test a web app. And I wanted to unclude factories in my tests to emulate users and not to create a user manually each time. So, I made gem install factory_girl, added required lined in my spec_helper, created a factory and included some lines in my spec file. And when running the test I get an error Failure/Error: FactoryGirl.build(:user) NameError: uninitialized constant User

Here is my spec_helper.rb

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
  config.expect_with :rspec do |expectations|
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end

My factories.rb file:

 FactoryGirl.define do
  factory :user do
    name "testuser"
    password "freestyle"
    inventory true
  end
end

And my test_spec file:

require "json"
require "selenium-webdriver"
require "rspec"
require "factory_girl"
FactoryGirl.find_definitions
include RSpec::Expectations

describe "MallSpec" do

  before(:all) do
    FactoryGirl.build(:user)
    @driver = Selenium::WebDriver.for :firefox
    @base_url = "http://localhost:9000/"
    @accept_next_alert = true
    @driver.manage.timeouts.implicit_wait = 30
    @driver.manage.window.resize_to(1301, 744)
    @verification_errors = []
end

My spec_file is in the root dir of the project. my factories.rb file is in /spec dir as well as the test_spec.rb itself. Can anyone help me with this issue or point what i am doing wrong?

2
What is a "user" in the context of your app?meagar

2 Answers

2
votes

If you don't actually have a User class but you want to use FactoryGirl to generate the attributes, you can override the class:

require "ostruct"

FactoryGirl.define do
  factory :user, class: OpenStruct do
    name "testuser"
    password "freestyle"
    inventory true

    # This isn't necessary, but it will prevent FactoryGirl from trying
    # to call #save on the built instance.
    to_create {}
  end
end

You can then use attributes_for if you just want a Hash, or create if you want an object that responds to methods like name.

You can use a library like Hashie::Mash if you want to generate JSON for use in your API:

factory :user, class: Hashie::Mash do
  # ...
end

# In your tests:
user_json = create(:user).to_json
1
votes

And when running the test I get an error Failure/Error: FactoryGirl.build(:user) NameError: uninitialized constant User

Your User class has to be defined. The following is a test with no User class defined:

require 'factory_girl' 

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

FactoryGirl.define do 
  factory :user do 
    name 'Alice'
    age 10
  end
end

describe "MallSpec" do
  let(:test_user) { FactoryGirl.build(:user) }

  describe "user's name" do
    it "equals 'Alice'" do
      expect(test_user.name).to eq('Alice')
    end
  end

end

--output:--
$ rspec 1.rb 
F

Failures:

  1) MallSpec user's name equals 'Alice'
     Failure/Error: let(:user) { FactoryGirl.build(:user) }
     NameError:
       uninitialized constant User
...

Adding a definition for the User class:

require 'factory_girl' 

#====NEW CODE=====
class User
  attr_accessor :name, :age
end
#=================

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

FactoryGirl.define do 
  factory :user do 
    name 'Alice'
    age 10
  end
end

describe "MallSpec" do
  let(:test_user) { FactoryGirl.build(:user) }

  describe "user's name" do
    it "equals 'Alice'" do
      expect(test_user.name).to eq('Alice')
    end
  end

end

--output:--
$ rspec 1.rb 
.

Finished in 0.0024 seconds (files took 0.35197 seconds to load)
1 example, 0 failures

I expect that the factory() method here:

  factory :user do 
    name 'Alice'
    age 10
  end

...does something like this:

def factory(model_name)
   target_class = constant_get(model_name.capitalize)

...in order to construct a real instance of the User class. In other words, factory_girl constructs instances of classes that already exist in your app--factory_girl does not mock a class.