Uninitialized constant Production::POverview (NameError)
from /Users/simon_zhu/.rvm/gems/ruby-2.1.0/gems/factory_girl-4.4.0/lib/factory_girl/syntax/default.rb:49:in `instance_eval'
from /Users/simon_zhu/.rvm/gems/ruby-2.1.0/gems/factory_girl-4.4.0/lib/factory_girl/syntax/default.rb:49:in `run'
from /Users/simon_zhu/.rvm/gems/ruby-2.1.0/gems/factory_girl-4.4.0/lib/factory_girl/syntax/default.rb:7:in `define'
from /Users/simon_zhu/Documents/original_version_carmel/carmel/spec/factories/poverview.rb:1:in `<top (required)>'
from /Users/simon_zhu/.rvm/gems/ruby-2.1.0/gems/factory_girl-4.4.0/lib/factory_girl/find_definitions.rb:20:in `block (2 levels) in find_definitions'
from /Users/simon_zhu/.rvm/gems/ruby-2.1.0/gems/factory_girl-4.4.0/lib/factory_girl/find_definitions.rb:19:in `each'
I have the following code:
poverview.rb (factory)
FactoryGirl.define do
factory :poverview, class: Production::POverview do
name "test"
status ["p", "d", "m"]
end
end
p_overview_controller_spec.rb (spec)
require 'spec_helper'
describe Production::POverviewController do
login_user
# GET Request to pod_info
describe 'GET pod_info' do
before(:each) do
#pods = Factory(:poverview)
get 'show', :format => :json, :name => #pods.name
get 'show', :format => :json, :status => #pods.status
end
it "should return the correct company when correct id is passed" do
body = JSON.parse(response.body)
for(pod in body[0])
if(pod['name'].eql? #pod.name)
#pod.status.should.include? pod['status']
end
end
end
end
This is my first time writing an integration test for Factory Girl and I have this uninitialized constant error.
Any Ideas how to solve this?
Also your test setup looks very odd. It definitely looks like you are confusing integration and controller test.
Here is a post to get you started. I recommend doing some more research on testing in rails.
https://semaphoreapp.com/blog/2014/02/11/rails-testing-antipatterns-controllers.html
Related
To learn API by using Rails I'm reading this tutorial.
In a part of RSpec test there is a method like this:
spec/support/authentication_helper.rb
module AuthenticationHelper
def sign_in(user)
header('Authorization', "Token token=\"#{user.authentication_token}\", email=\"#{user.email}\"")
end
def create_and_sign_in_user
user = FactoryGirl.create(:user)
sign_in(user)
user
end
alias_method :create_and_sign_in_another_user, :create_and_sign_in_user
end
RSpec.configure do |config|
config.include AuthenticationHelper, type: :api
end
And the test failed by undefined method `header'.
Where is this header method defined?
This is the whole source code of this tutorial.
https://github.com/vasilakisfil/rails_tutorial_api/
spec/apis/users_spec.rb
require 'rails_helper'
describe Api::V1::UsersController, type: :api do
context :show do
before do
create_and_sign_in_user
#user = FactoryGirl.create(:user)
get api_v1_user_path(#user.id), format: :json
end
it 'returns the correct status' do
expect(last_response.status).to eql(200)
end
it 'returns the data in the body' do
body = HashWithIndifferentAccess.new(MultiJson.load(last_response.body))
expect(body[:user][:name]).to eql(#user.name)
expect(body[:user][:updated_at]).to eql(#user.updated_at.iso8601)
end
end
end
StackTrace
1) Api::V1::UsersController show returns the correct status
Failure/Error: create_and_sign_in_user
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::ApiV1UsersController::Show:0x007fcbfec91d60>
# ./spec/support/authentication_helper.rb:4:in `sign_in'
# ./spec/support/authentication_helper.rb:9:in `create_and_sign_in_user'
# ./spec/apis/user_spec.rb:6:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (2 levels) in <top (required)>'
# -e:1:in `<main>'
2) Api::V1::UsersController show returns the data in the body
Failure/Error: create_and_sign_in_user
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::ApiV1UsersController::Show:0x007fcbfb7cfa28>
# ./spec/support/authentication_helper.rb:4:in `sign_in'
# ./spec/support/authentication_helper.rb:9:in `create_and_sign_in_user'
# ./spec/apis/user_spec.rb:6:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:39:in `block (3 levels) in <top (required)>'
# ./spec/rails_helper.rb:38:in `block (2 levels) in <top (required)>'
# -e:1:in `<main>'
I had to add api_helper.rb to use the methods.
module ApiHelper
include Rack::Test::Methods
def app
Rails.application
end
end
RSpec.configure do |config|
config.include ApiHelper, type: :api #apply to all spec for apis folder
config.include Rails.application.routes.url_helpers, type: :api
end
Here is source code in Github.
https://github.com/vasilakisfil/rails_tutorial_api/blob/008af67e88897a5bcde714ce13d39a26ec70fba7/spec/support/api_helper.rb
In spec/support/auth_helpers.rb, you can try something like this
module AuthHelpers
def authenticate_with_user(user)
request.headers['Authorization'] = "Token token=#{user.token}, email=#{user.email}"
end
def clear_authentication_token
request.headers['Authorization'] = nil
end
end
In Rspec's spec/rails_helper.rb
Rspec.configure do |config|
config.include AuthHelpers, file_path: /spec\/apis/
end
An example test in spec/apis/users_controller_spec.rb:
require 'rails_helper'
describe Api::V1::UsersController, type: :controller do
let(:user) { create(:user) }
context 'signed in' do
before do
authenticate_with_user user
end
it 'does something' # tests here
end
end
Hope it helps!
Edit: Note the type: :controller is important
I am creating a set of tests with two factories, see below:
spec/factories/page.rb
FactoryGirl.define do
factory :page do
title "Example Title"
content "Here is some sample content"
published_on "2013-06-02 02:28:12"
end
factory :page_invalid do
title ""
content ""
published_on "2013-06-02 02:28:12"
end
end
However, in spec/controllers/page_controller_spec.rb, the following test throws an error:
describe "with invalid params" do
it "does not save the new page in the database" do
expect {
post :create, {page: attributes_for(:page_invalid)}, valid_session
}.to_not change(Page, :count).by(1)
end
The error:
1) Api::PagesController POST create with invalid params does not save the new page in the database
Failure/Error: post :create, {page: attributes_for(:page_invalid)}, valid_session
NameError:
uninitialized constant PageInvalid
# ./spec/controllers/pages_controller_spec.rb:78:in `block (5 levels) in <top (required)>'
# ./spec/controllers/pages_controller_spec.rb:77:in `block (4 levels) in <top (required)>'
This code is analogous to code in Everyday Rails Rspec so I'm not sure why the page_invalid factory isn't being recognized.
Try this:
FactoryGirl.define do
factory :page do
title "Example Title"
content "Here is some sample content"
published_on "2013-06-02 02:28:12"
end
factory :page_invalid, :class => "Page" do
title ""
content ""
published_on "2013-06-02 02:28:12"
end
end
Notice the :class => option on your :page_invalid factory.
I am a bit confused here. I am trying to do TDD and have run into an issue. Rspec is telling me the following-
1) Sammiches GET /sammiches display some sammiches
Failure/Error: visit sammiches_path
NameError:
undefined local variable or method `sammiches_path' for #<RSpec::Core::ExampleGroup::Nested_4::Nested_1:0x007fa7afcfed70>
# ./spec/requests/sammiches_spec.rb:7:in `block (3 levels) in <top (required)>'
2) Sammiches GET /sammiches creates a new sammich
Failure/Error: visit sammiches_path
NameError:
undefined local variable or method `sammiches_path' for #<RSpec::Core::ExampleGroup::Nested_4::Nested_1:0x007fa7ae11e6f0>
# ./spec/requests/sammiches_spec.rb:12:in `block (3 levels) in <top (required)>'
This is what my spec file looks like
require 'spec_helper'
describe "Sammiches" do
describe "GET /sammiches" do
it "display some sammiches" do
#sammich = Sammich.create :name => 'bacon'
visit sammiches_path
page.should have_content 'bacon'
end
it "creates a new sammich" do
visit sammiches_path
fill_in 'Sammich', :with => 'lechuga'
click_button 'add Sammich'
current_path.should = root_path
page.should have_content 'lechuga'
save_and_open_page
end
end
end
My routes are -
sammiches_index GET /sammiches/index(.:format) sammiches#index
Sammiches GET /Sammiches(.:format) Sammiches#index
POST /Sammiches(.:format) Sammiches#create
new_Sammich GET /Sammiches/new(.:format) Sammiches#new
edit_Sammich GET /Sammiches/:id/edit(.:format) Sammiches#edit
Sammich GET /Sammiches/:id(.:format) Sammiches#show
PUT /Sammiches/:id(.:format) Sammiches#update
DELETE /Sammiches/:id(.:format) Sammiches#destroy
root / Sammiches#index
Routes-
Sammiches::Application.routes.draw do
get "Sammiches/index"
resources :sammiches
root :to => 'Sammiches#index'
New Error-
1) Sammiches GET /sammiches creates a new sammich
Failure/Error: visit sammiches_path
ActionView::Template::Error:
undefined method `sammich' for #<Sammich:0x007fd0007d2f80>
# ./app/views/sammiches/index.html.erb:4:in `block in _app_views_sammiches_index_html_erb___2703584807867277870_70265660050820'
# ./app/views/sammiches/index.html.erb:2:in `_app_views_sammiches_index_html_erb___2703584807867277870_70265660050820'
# ./spec/requests/sammiches_spec.rb:12:in `block (3 levels) in <top (required)>'
2) Sammiches GET /sammiches display some sammiches
Failure/Error: visit sammiches_path
ActionView::Template::Error:
undefined method `sammich' for #<Sammich:0x007fd00006f4f0>
# ./app/views/sammiches/index.html.erb:4:in `block in _app_views_sammiches_index_html_erb___2703584807867277870_70265660050820'
# ./app/views/sammiches/index.html.erb:2:in `_app_views_sammiches_index_html_erb___2703584807867277870_70265660050820'
# ./spec/requests/sammiches_spec.rb:7:in `block (3 levels) in <top (required)>'
I am at a bit of a loss here. Any advice would be greatly appreciated.
Thanks.
You seem to have added resources :Sammiches in config/routes.rb.
Change it to resources :sammiches. Sticking to the convention, helps. :)
Your route file should look like:
Sammiches::Application.routes.draw do
resources :sammiches
root :to => 'sammiches#index'
I can't figure out why this RSpec test fails. Any advice? I'm new-ish to FactoryGirl, RSpec, and TDD in general.
Controller:
def update
#vendor = current_user.vendors.find(params[:id])
if #vendor.update_attributes(params[:vendor])
redirect_to vendor_path(#vendor)
else
render 'edit'
end
end
Test:
require 'spec_helper'
describe VendorsController do
login_user
before :each do
#user = subject.current_user
#vendor = FactoryGirl.create(:vendor, :user => #user)
end
[...]
describe 'POST update' do
def do_update
post :update, :id => #vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
end
[...]
it 'should update a given vendor' do
do_update
#vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
end
end
end
Factory:
FactoryGirl.define do
factory :vendor do
name 'Widget Vendor'
user
end
end
The Failure:
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: #vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
(#<Vendor:0x007faeb75e77d0>).update_attributes({:name=>"Widget Vendor"})
expected: 1 time
received: 0 times
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
Update:
I'm a little closer, now. I changed the test to the following:
it 'should update a given vendor' do
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
And the new error is:
Failures:
1) VendorsController POST update should update a given vendor
Failure/Error: post :update, :id => #vendor.id, :vendor => FactoryGirl.attributes_for(:vendor)
#<Vendor:0x007ff30d765900> received :update_attributes with unexpected arguments
expected: ({:name=>"Widget Vendor"})
got: ({"name"=>"Widget Vendor"})
# ./app/controllers/vendors_controller.rb:33:in `update'
# ./spec/controllers/vendors_controller_spec.rb:98:in `do_update'
# ./spec/controllers/vendors_controller_spec.rb:108:in `block (3 levels) in <top (required)>'
Answer...?
Well, this worked. There has to be a better way of doing this, though:
Vendor.any_instance.should_receive(:update_attributes).with(JSON.parse(FactoryGirl.attributes_for(:vendor).to_json)).and_return(true)
I think you are doing it wrong.
The #vendor object in specs is another one that in your controller, so it doesn't receive "update_attributes" method.
You can try this (rspec 2.5+ probably):
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
Or you can check if object attributes has changed:
expect{
do_update
}.to change(...)
I believe you need to set your expectations before posting the request; otherwise, by the time it hits your expectation the object has already been set. So move do_update after your should_receive line:
it 'should update a given vendor' do
#vendor.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor))
do_update
end
You can use the Hash stringify keys method in rails:
Vendor.any_instance.should_receive(:update_attributes).with(FactoryGirl.attributes_for(:vendor).stringify_keys)
Here is the rspec code for testing show in customers controller:
it "'show' should be successful" do
#category = Factory(:category)
#sales = Factory(:user)
#customer = Factory(:customer, :category1_id => category.id, :sales_id => sales.id)
category = mock_model('Category')
sales = mock_model('User')
customer = mock_model(Category, :sales_id => sales.id, :category1_id => category.id)
get 'show' , :id => customer.id
response.should be_success
end
Here is the error in rspec:
CustomersController GET customer page 'show' should be successful
Failure/Error: get 'show' , :id => customer.id
ActiveRecord::RecordNotFound:
Couldn't find Customer with id=1003
# c:in `find'
# ./app/controllers/customers_controller.rb:59:in `show'
# ./spec/controllers/customers_controller_spec.rb:50:in `block (3 levels) in <top (required)>'
The rspec test passes with the real record created by Factory (see #ed in rspec code)
What's wrong with the mock? Thanks.
The spec is failing inside the controller's action which doesn't know anything about your mocks unless you told it explicitly.
Add this to your spec, before the get statement.
Customer.should_receive(:find).and_return(customer)