Here is the failed spec code for create in customer controller:
describe CustomersController do
before(:each) do
#the following recognizes that there is a before filter without execution of it.
controller.should_receive(:require_signin)
controller.should_receive(:require_employee)
end
render_views
describe "'create' successful" do
before(:each) do
category = Factory(:category)
sales = Factory(:user)
#customer = Factory.attributes_for(:customer, :category1_id => category.id, :sales_id => sales.id)
session[:sales] = true
session[:user_id] = sales.id
session[:user_name] = sales.name
session[:page_step] = 1
session['page1'] = customers_path
end
it "should create one customer record" do
lambda do
post 'create', #customer
end.should change(Customer, :count).by(1)
end
it "should redirect to customers path" do
put 'create', #customer
flash[:notice].should_not be_nil
response.should redirect_to(customers_path)
end
end
end
The customer has both sales id and category id which belong to user and category table respectively.
Here is the spec failure error:
1) CustomersController GET customer page 'create' successful should create one customer record
Failure/Error: lambda do
count should have been changed by 1, but was changed by 0
# ./spec/controllers/customers_controller_spec.rb:37:in `block (4 levels) in <top (required)>'
2) CustomersController GET customer page 'create' successful should redirect to customers path
Failure/Error: flash[:notice].should_not be_nil
expected: not nil
got: nil
# ./spec/controllers/customers_controller_spec.rb:44:in `block (4 levels) in <top (required)>'
Here is the app code for create in customer controller:
def create
if session[:sales]
#customer = Customer.new(params[:customer], :as => :roles_new_update)
#customer.sales_id = session[:user_id]
if #customer.save
#message = "New customer #{params[:name]} was created. Please check it out"
#subject = "New customer #{params[:name]} was created BY {#session[:user_name]}"
UserMailer.notify_tl_dh_ch_ceo(#message, #subject, session[:user_id])
redirect_to session[('page' + session[:page_step].to_s).to_sym], :notice => 'Customer was created successfaully!'
else
render 'new', :notice => 'Customer was not saved!'
end
end
end
Here is the code in factories.rb:
Factory.define :customer do |c|
c.name "test customer"
c.short_name "test"
c.email "t#acom.com"
c.phone "12345678"
c.cell "1234567890"
c.active 1
c.category1_id 2
c.sales_id 1
c.address "1276 S. Highland Ave, Lombard, IL 67034"
c.contact "Jun C"
end
Factory.define :category do |c|
c.name "category name"
c.description "test category"
c.active true
end
Factory.define :user do |user|
user.name "Test User"
user.email "test#test.com"
user.password "password1"
user.password_confirmation "password1"
user.status "active"
user.user_type "employee"
end
It seems that the error was caused by #customer.save returning false and the code for "if #customer.save" was not executed. So the problem may be with the #customer generated by Factory which seems good to me. The code is executed without any problem when saving a customer.
Any suggestions? Thanks.
I would break this up into two specific tests. Right now you're unsure of two things:
is the customer is being told to save itself?
Is there a validation that is preventing customer from being saved?
The quickest path is to change #customer.save to #customer.save! and see if there are any exceptions raised (it will do so if a validation failed).
I recommend you split this up though. To test #1, in the controller spec:
it "should tell the customer to save itself when there is a session[:sales]" do
session[:sales] = true
customer_mock = double(:customer)
customer_mock.should_receive(:sales_id=)
customer_mock.should_receive(:save).and_return(:true)
Customer.stub(:new => cutomer_mock)
post 'create'
end
Then in your customer_spec, test out:
it "should be valid with factory specs" do
customer = Customer.new(Factory.attributes_for(:customer))
customer.should be_valid
end
post :create, :customer => #customer
solves the problem with above.
Related
I previously fixed an issue with some code that works though it is a little ugly. Problem now is that it breaks my tests! The idea here is that I can create a Campaign and associate 1 zip-file and one-to-many pdfs.
Previous question and solution:
Rails 4.2: Unknown Attribute or Server Error in Log
Here is the failure message:
console
1) CampaignsController POST #create with valid params
Failure/Error: post :create, campaign: attributes_for(:campaign)
ActiveRecord::RecordNotFound:
Couldn't find Uploadzip with 'id'=
# ./app/controllers/campaigns_controller.rb:15:in `create'
# ./spec/controllers/campaigns_controller_spec.rb:36:in `block (4 levels) in <top (required)>'
..and the rest of the code.
spec/factories/campaigns.rb
FactoryGirl.define do
factory :campaign do |x|
x.sequence(:name) { |y| "Rockfest 201#{y} Orange County" }
x.sequence(:comment) { |y| "Total attendance is #{y}" }
end
end
spec/controllers/campaigns_controller.rb
describe "POST #create" do
context "with valid params" do
before(:each) do
post :create, campaign: attributes_for(:campaign)
end
.........
end
app/controllers/campaigns_controller.rb
class CampaignsController < ApplicationController
......................
def create
#campaign = Campaign.new(campaign_params)
if #campaign.save
zip = Uploadzip.find(params[:uploadzip_id])
zip.campaign = #campaign
zip.save
flash[:success] = "Campaign Successfully Launched!"
redirect_to #campaign
else
................
end
end
.......................
private
def campaign_params
params.require(:campaign).permit(:name, :comment, :campaign_id, uploadpdf_ids: [])
end
end
This appears simple and I assume it is, yet I've tried quit a few things and can't seem to get it to pass. How would I support the new controller logic in this test? Any help is appreciated.
UPDATE
With zetitic's advice, I created the following code in which successfully passes.
before(:each) do
#uploadzip = create(:uploadzip)
post :create, campaign: attributes_for(:campaign), uploadzip_id: #uploadzip
end
Add the uploadedzip_id to the posted params:
before(:each) do
post :create, campaign: attributes_for(:campaign), uploadedzip_id: 123456
end
Been trying to figure this out for a while now, but can't seem to go green. Here is the rspec error that I am getting:
1) UsersController POST create with valid parameters creates a new user
Failure/Error: expect {post :create, user}.to change(User, :count).by 1
count should have been changed by 1, but was changed by 0
# ./spec/controllers/users_controllers_spec.rb:36:in `block (4 levels) in <top
(required)>'
Here is my relevant test in the users_controllers_spec:
describe UsersController do
let(:user) {FactoryGirl.create :user}
context 'POST create' do
context 'with valid parameters' do
before {post :create, user}
let(:user) {FactoryGirl.build :user}
it 'creates a new user' do
expect {post :create, user}.to change(User, :count).by 1
end
it {should respond_with 200}
end
And here is my users_controller create method:
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome #{#user.name.capitalize}! Please complete your profile."
redirect_to profile_path(current_user)
else
render :new
end
end
Also, here is my factories.rb file:
FactoryGirl.define do
factory :user do
name "John"
email "John#example.com"
password "password"
password_confirmation "password"
end
end
What am I missing? I feel like it is something really obvious, but I can't seem to figure it out. Any help would be much appreciated.
Your test involves creating a second user with FactoryGirl, but the creation of the second user is failing because the email is the same as the first and you have a uniqueness validation on that attribute.
You can either not create the first user at all or you'll need to make the emails different (e.g. by passing in an email parameter to your FactoryGirl call or changing the Factory to make each email address unique).
I'm on section 10.3.1 "User Index" of Ruby on Rails 3 Tutorial. I have one test that refuses to pass and I have researched the error extensively and can't seem to get it to pass.
Here is the error:
1) UsersController GET 'index' for signed-in users should have an element for each user
Failure/Error: response.should have_selector("li", :content => user.name)
NoMethodError:
undefined method name' for nil:NilClass
# ./spec/controllers/users_controller_spec.rb:39:inblock (5 levels) in '
# ./spec/controllers/users_controller_spec.rb:38:in each'
# ./spec/controllers/users_controller_spec.rb:38:inblock (4 levels) in '
I have tried a test to ensure that the user is returning an object instead of an array...it is. I have checked my sign_in and test_sign_in methods. I can probably move on, but fails tests drive me crazy.
Here is my users_controller_spec.rb code:
describe "for signed-in users" do
before(:each) do
#user = test_sign_in(Factory(:user))
second = Factory(:user, :name => "Bob", :email => "another#example.com")
third = Factory(:user, :name => "Ben", :email => "another#example.net")
#users = [#users, second, third]
end
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector("title", :content => "All users")
end
it "should have an element for each user" do
get :index
#users.each do |user|
response.should have_selector("li", :content => user.name)
end
end
end
end
Please help!!!
I actually just solved this. In my code for # users = [#user, second, third] I misspelled #user with # users
I was wondering if i could have some feedbacks with the controller spec bellow. In fact i'm new when writing specs and controller's spec are way different from model's spec ! So i'm wondering if i may not go in the wrong direction...
subjects_controller.rb
def show
#subject = Subject.find(params[:id])
if #subject.trusted?(current_user)
#messages = #subject.messages
else
#messages = #subject.messages.public
#messages = #messages + #subject.messages.where(:user_ids => current_user.id)
#messages.uniq!
end
# sort the list
#messages = #messages.sort_by(&:created_at).reverse
if !#subject.company.id == current_user.company.id
redirect_to(subjects_path, :notice => "Invalid subject")
end
end
subjects_controller_spec.rb
require 'spec_helper'
describe SubjectsController do
before(:each) do
#subject = mock_model(Subject)
end
context "for signed users" do
before(:each) do
#current_user = sign_in Factory(:user)
end
context "GET #show" do
before(:each) do
Subject.stub!(:find, #subject).and_return(#subject)
end
context "when current_user is trusted" do
before(:each) do
messages = []
company = mock_model(Company)
#subject.should_receive(:trusted?).and_return(true)
#subject.should_receive(:messages).and_return(messages)
#subject.should_receive(:company).and_return(company)
end
it "should render success" do
get :show, :id => #subject
response.should be_success
end
end
context "when current_user is not trusted" do
before(:each) do
messages = []
company = mock_model(Company)
#subject.should_receive(:trusted?).and_return(false)
#subject.should_receive(:messages).and_return(messages)
messages.should_receive(:public).and_return(messages)
#subject.should_receive(:messages).and_return(messages)
messages.should_receive(:where).and_return(messages)
#subject.should_receive(:company).and_return(company)
end
it "should render success" do
get :show, :id => #subject
response.should be_success
end
end
context "when subject's company is not equal to current_user's company" do
# I have no idea of how to implement ==
end
end
end
end
Factories.rb
Factory.define :user do |u|
u.first_name 'Test User' #
u.username 'Test User' #
u.surname 'TheTest' #
u.email 'foo#foobar.com' #
u.password 'please' #
u.confirmed_at Time.now #
end
As far as I can tell you're on the right path. The basic idea is to completely isolate your controller code from model and view in these tests. You appear to be doing that--stubbing and mocking model interaction.
Don't write RSpec controller specs at all. Use Cucumber stories instead. Much easier, and you get better coverage.
I'm seeing some strange behavior when I'm trying to stub out some methods. I'm using rails 3.0.3 and rspec 2.3.0
Here is the relevant section of the spec file
require 'spec_helper'
include Authlogic::TestCase
describe PrizesController do
before do
activate_authlogic
#manager = Factory.create(:valid_manager, :name => "Test Manager ")
UserSession.create #manager
end
def mock_prize(stubs={})
(#mock_prize ||= mock_model(Prize, :point_cost => 100).as_null_object).tap do |prize|
prize.stub(stubs) unless stubs.empty?
end
end
def mock_consumable(stubs={})
(#mock_consumable ||= mock_model(Consumable).as_null_object).tap do |consumable|
consumable.stub(stubs) unless stubs.empty?
end
end
describe "GET buy_this" do
it "assigns the requested prize as #prize and requested consumable as #consumable if the player has enough points" do
Prize.stub(:find).with("37") { mock_prize }
#manager.should_receive(:available_points).and_return(1000)
get :buy_this, :id => "37", :user_id => #manager.id
assigns(:prize).point_cost.should eq(100)
assigns(:prize).should be(mock_prize)
assigns(:consumable).should_not be_nil
end
it "assigns the requested prize as #prize and no consumable as #consumable if the player does not have enough points" do
Prize.stub(:find).with("37") { mock_prize }
#manager.should_receive(:available_points).and_return(10)
get :buy_this, :id => "37", :user_id => #manager.id
assigns(:prize).point_cost.should eq(100)
assigns(:prize).should be(mock_prize)
assigns(:consumable).should be_nil
end
end
And the controller method:
def buy_this
#prize = Prize.find(params[:id])
user = User.find(params[:user_id]) if params[:user_id]
user ||= current_user
flash[:notice] = ("Attempting to redeem points for a prize")
if user.available_points > #prize.point_cost
#consumable = user.consumables.create(:kind => #prize.consumable_kind, :description => #prize.consumable_description, :redemption_message => #prize.consumable_redemption_message)
point_record = #consumable.create_point_record(:redeemed_points => #prize.point_cost)
point_record.user = user
point_record.save
flash[:success] = "You successfully redeemed #{#prize.point_cost} points for #{#prize.name}"
else
flash[:error] = "Sorry, you don't seem to have enough points to buy this"
end
redirect_to prizes_path
end
The tests fail and this is the output...
1) PrizesController GET buy_this assigns the requested prize as #prize and requested consumable as #consumable if the player has enough points
Failure/Error: assigns(:consumable).should_not be_nil
expected not nil, got nil
# ./spec/controllers/prizes_controller_spec.rb:39
2) PrizesController GET buy_this assigns the requested prize as #prize and no consumable as #consumable if the player does not have enough points
Failure/Error: #manager.should_receive(:available_points).and_return(10)
(#<User:0x10706b000>).available_points(any args)
expected: 1 time
received: 0 times
# ./spec/controllers/prizes_controller_spec.rb:44
Any ideas about this? I'm totally stumped why the two tests calling the same method with the same parameters would fail in different ways (not to mention, I don't understand why they are failing at all...).