Testing Nested Resources Controller with RSpec - count doesn't change by 1 - ruby-on-rails-3

I have nested resources:
resources :portfolios do
resources :asset_actions
end
And following RSpec Controller: asset_actions_controller_spec.rb
before(:each) do
#portfolio = Factory(:portfolio)
end
describe "POST create" do
describe "with valid params" do
it "creates a new AssetAction" do
expect {
post :create, :asset_action => valid_attributes, :portfolio_id => #portfolio.id
##portfolio.asset_actions.create! valid_attributes #WORKS correctly, but this is Model
}.to change(#portfolio.asset_actions, :count).by(1)
end
end
end
While running Spec I got the following error:
Failure/Error: expect {
count should have been changed by 1, but was changed by 0
I can't find the reason for this failure. Any suggestions?
Notes: Rails 3.1.3, Ruby 1.9.3p5, RSpec 2.8.0

I think the problem is that #portfolio hasn't changed because it is a local variable. It's stored in memory and you've made changes to the database. So, you need to reload #portfolio to see it change. Try something like this:
describe "POST create" do
describe "with valid params" do
it "creates a new AssetAction" do
post :create, :asset_action => valid_attributes, :portfolio_id => #portfolio.id
expect { #portfolio.reload }.to change(#portfolio.asset_actions, :count).by(1)
end
end
end

Related

Rspec testing in rails3

I have a Queues controller and and QueueItems controller in my rails
application. In routes I have defined as below
match 'queues/:queue_id/next', :to=> 'queueitems#next'
In my QueueItems Controller I have a next action and it assigns an
instance variable.
def next
#queue = "Regular"
#other stuffs related to regular
end
How do I test this in Rspec. I am pretty very new to Rspec. Please help.
I tried like the below
describe QueuesController do
describe "next " do
it "routes /queues/:queue_id/next" do
{ :get => "/queues/regular_queue/next" }.should route_to(
:controller => "queue_items",
:action => "next",
:queue_id => "regular_queue",
:format => "json"
)
assigns(:queue).should_not be_nil
expect(response).to be_success
end
end
But it is not at all coming inside my next action in controller.
Update #2
spec/controllers/queue_items_controller_spec.rb
require 'spec_helper'
describe QueueItemsController do
describe 'GET next' do
it 'assigns #queue' do
get :next, format: :json
expect(assigns[:queue]).to eq('regular')
end
end
end
queue_items_controller.rb
def next
puts "Inside next action..."
#queue = "regular"
end
routes.rb
get '/queues/:queue_id/next', :to => 'queue_items#next', :format=>'json'
rake routes
GET /queues/:queue_id/next(.:format) queue_items#next {:format=>"json"}
/queues/:queue_id/delete(.:format) queue_items#delete {:method=>:delete, :format=>"json"}
/queues/:queue_id/clear(.:format) queue_items#clear {:format=>"json"}
First of all change match to get or post - it is better to use exactly verb. Let's say it is get.
Action next is in QueueItemsController so test should be in this queue_items_controller_spec.rb file (and in folder spec/controlers).
and test might be similar to
describe QueueItemsController do
describe "GET next " do
it "responses json" do
get :next, format: :json
expect(response).to be_success
end
it "does not response html" do
get :next, format: :html
expect(response).not_to be_success # or define more exactly response
end
it 'assigns #queue' do
get :next, format: :json
expect(assigns[:queue]).to eq('Regular')
end
end
end
if you would like to test your routes you should follow this articles:
https://www.relishapp.com/rspec/rspec-rails/v/2-14/docs/routing-specs
https://www.relishapp.com/rspec/rspec-rails/docs/routing-specs/route-to-matcher

How do I pass a params parameter into an rspec controller test?

I have the following rspec test:
def valid_attributes
{ "product_id" => "1" }
end
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, {:line_item => valid_attributes}, valid_session #my valid_session is blank
}.to change(LineItem, :count).by(1)
end
Which fails with this error:
1) LineItemsController POST create with valid params redirects to the created line_item
Failure/Error: post :create, {:line_item => valid_attributes}, valid_session
ActiveRecord::RecordNotFound:
Couldn't find Product without an ID
# ./app/controllers/line_items_controller.rb:44:in `create'
# ./spec/controllers/line_items_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
This is my controller's create action:
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render json: #line_item.cart, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
As you can see, my action expects a product_id from the request's params object. How should I work this product_id into my rspec test?
I've tried placing this before statement:
before(:each) do
ApplicationController.any_instance.stub(:product).and_return(#product = mock('product'))
end
. . . but it changes nothing. I am missing some rspec concept here somewhere.
Try like this:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => 1
}.to change(LineItem, :count).by(1)
end
Hope it helps.
I ended up resolving my issue by using a fixture instead of attempting to mock the solution as suggested in another answer.
The reason for this is that the controller does the query to get information from the database: product = Product.find(params[:product_id]) and I found a fixture-based solution was quicker to resolve my problem than one using a mock and I could not figure out how to stub the query quickly (the fixtures also help with another test on the controller so it eventually helped anyway.
For reference:
I referenced my fixture with this line toward the top of the test: fixtures :products
I changed my test to:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => products(:one).id
}.to change(LineItem, :count).by(1)
end
And here is my fixture file, products.yml:
one:
name: FirstProduct
price: 1.23
two:
name: SecondProduct
price: 4.56

why controller var isn't available within a test?

I'm trying to follow Michael Hartl's Ruby on Rails Tutorial in http://ruby.railstutorial.org/chapters/sign-in-sign-out, but with some changes to practice, above all, some variations and the Test::Unit framework. In the tutorial, RSpec is used, while I'm trying to stick to Test::Unit + Shoulda-context.
In chapter 9 I'm suposed to pass some functional tests that use a var called 'controller', but my tests don't work as they find out that 'controller' doesn't exist. This is what I get:
marcel#pua:~/Desenvolupament/Rails3Examples/ror_tutorial$ rake
test:recent Loaded suite
/home/marcel/.rvm/gems/ruby-1.9.2-p290/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started F
=============================================================================== Failure: test: POST 'create' with valid signin (email and password)
should redirect to the user show page. (SessionsControllerTest)
[test/functional/sessions_controller_test.rb:58]: Expected at least 1
element matching "title", found 0. is not true.
=============================================================================== E
=============================================================================== Error: test: POST 'create' with valid signin (email and password)
should sign in the user. (SessionsControllerTest): NameError:
undefined local variable or method `controller' for
test/functional/sessions_controller_test.rb:53:in `block (3 levels) in <class:SessionsControllerTest>'
=============================================================================== Finished in 0.957865676 seconds. 7 tests, 6 assertions, 1 failures, 1
errors, 0 pendings, 0 omissions, 0 notifications 0% passed
7.31 tests/s, 6.26 assertions/s rake aborted! Command failed with status (1): [/home/marcel/.rvm/rubies/ruby-1.9.2-p290/b...] Tasks: TOP
=> test:recent (See full trace by running task with --trace)
This is the original (RSpec) test:
describe SessionsController do
...
describe "POST 'create'" do
...
describe "with valid email and password" do
before(:each) do
#user = Factory(:user)
#attr = { :email => #user.email, :password => #user.password }
end
it "should sign the user in" do
post :create, :session => #attr
controller.current_user.should == #user
controller.should be_signed_in
end
it "should redirect to the user show page" do
post :create, :session => #attr
response.should redirect_to(user_path(#user))
end
end
end
end
and this is my translated (into Test::Unit + Sholuda-context) test:
class SessionsControllerTest < ActionController::TestCase
context "POST 'create'" do
context "with valid signin (email and password)" do
setup do
#attr = {email: "test#email.tst", password: "testpwd"}
#user=User.create! #attr.merge!({name: "test_user", password_confirmation: "testpwd"})
end
should "sign in the user" do
post :create, :session => #attr
assert_equal #user, controller.current_user
end
should "redirect to the user show page" do
post :create, :session => #attr
assert_select "title", /Show/
end
end
end
end
Has anybody any idea how to make my test work?
Looking at the official Rails testing guide at http://guides.rubyonrails.org/testing.html, I've seen that an instance variable called #controller is enabled in functional tests. so, the Test::Unit version should be:
should "sign in the user" do
post :create, :session => #attr
assert_equal #user, #controller.current_user
end

I am having trouble testing my controller's update action using Rspec, what am I doing wrong?

I am trying to test the failing branch of the update action on my controller but I am having trouble with the test. This is what I have and it fails on the last
describe "PUT 'article/:id'" do
.
.
.
describe "with invalid params" do
it "should find the article and return the object" do
Article.stub(:find).with("1").and_return(#article)
end
it "should update the article with new attributes" do
Article.stub(:update_attributes).and_return(false)
end
it "should render the edit form" do
response.should render_template("edit")
end
end
end
Any ideas as to why the last part fails to render the template?
You're splitting up the parts of your test incorrectly. Each it call is actually a new example and the state is reset before/after each one.
What you should be doing is:
describe "with invalid params" do
before do
#article = Article.create(valid_params_go_here)
end
it "should find the article and return the object" do
put :update, { :id => #article.id, :article => { :title => "" } }
response.should render_template("edit")
end
end
By doing it this way, the #article is set up before hand (although you could use a mock one if you really wanted to) and the request to the update action and the assertion that it actually renders the edit template all happen in the one example.
For people who are coming here in 2018, some updates(pun not intended) have been made. It's important to include "params" before listing the params. Additionally, you should use expect and not "should" since it will be deprecated in Rails 6.0.
describe "with invalid params" do
before(:each) do
#article = Article.create(valid_params_go_here)
end
describe "PATCH update/:id" do
it "should find the article and return the object" do
put :update, params: { id: #article.id, article: { title: "" } }
expect(response).to be_redirect
end
end

RSpec and weird tests results

I'm trying to make a simple app. When Im testing it in browser everytyhing works just fine. Howerver, when I try to run some tests with RSpec (2.5) it fails when it comes to :create test for controller.
Here's my create method:
def create
#website = Website.new(params[:website])
if #website.save
flash[:notice] = "Website created."
redirect_to(:action => 'list')
else
render('new')
end
end
The controller test:
describe WebsitesController do
render_views
.
.
.
describe "POST 'create'" do
before(:each) do
#attr = { :adres => "www.excc.pl", :opis => "aaa "*22, :tagi => "aaa aaa aaa",
:preview => File.new(Rails.root + 'spec/fixtures/rails.png'),
:preview_mini => File.new(Rails.root + 'spec/fixtures/rails.png')}
end
describe "success" do
it "should have the right title" do
response.should have_selector("title", :content=>"Lista witryn w portfolio")
end
end
.
.
.
The result of this test:
1) WebsitesController POST 'create' should have the right title
Failure/Error: response.should have_selector("title", :content=>"Lista witryn w portfolio")
expected following output to contain a <title>Lista witryn w portfolio</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/websites_controller_spec.rb:34:in `block (4 levels) in
websites_controller_spec.rb:34 refers to create method
However, this test is passed correctly (for incorrect data it should be redirected back to 'new' site with specified title):
it "should have the right title" do
post :create, :website => #attr.merge(:adres => "")
response.should have_selector("title", :content=>"Dodaj stronÄ™ WWW")
end
The second problem is...
There was a time when I've got a test result like this:
<html><body>You are being redire cted.</body></html>
... which was causing me to pull my hair out for some time until I've done sth (I don't really know what) and it was gone. Yet, it makes me scared like hell when I think that it can come back in future an ruin my happiness.
Any thoughts on this would be greatly appreciated.
It's hard to know what is being asked here, but I believe the issue is that you are not setting the conditions for success/failure. If I understand correctly, when you pass in an blank :adres attribute, the save should fail and the page should render the list action. So you want to stub the create method and return true or false depending on the expected result:
it "succeeds" do
#website = mock_model(Website,:save=>true)
Website.stub(:new) { #website }
post :create, :website => {}
# redirects
response.should have_selector("etc etc")
end
it "fails" do
#website = mock_model(Website,:save=>false)
Website.stub(:new) { #website }
post :create, :website => {}
# renders 'new'
response.should_not have_selector("etc etc")
end
Testing of the validity of the parameters should be performed in the model spec:
#website = Website.new(:adres=>"")
#website.should_not be_valid