Testing Rails nested controllers - ruby-on-rails

I have an Admin model which can manage Organizations.
I have an AdminController with a simple index action and a child Admin::OrganizationsController controller which I'm trying to test.
The test for the canonical show action on this child controller passes without errors:
describe "GET show" do
it "assigns the requested organization as #organization" do
org = FactoryGirl.create(:organization)
get :show, id: org.id # <---- this works
expect(assigns(:organization)).to eq(org)
end
end
but when I try to test the destroy action, I get an error I'm not able to understand (hence resolve):
describe "DELETE destroy" do
it "destroys the requested organization" do
org = FactoryGirl.create(:organization)
delete :destroy, id: org.id # <---- (I tried to use org.id.to_param, unsuccessfully)
# ...rest of the test
end
end
with error:
Failure/Error: expect { delete :destroy, id: org.id }.to change(Organization, :count).by(-1)
NameError:
undefined local variable or method `organizations_url' for #<Admin::OrganizationsController:0x007fefe1622248>
I suspect this has to do with my controller being "nested" (it needs something like admin_organizations_url I guess).
Any help?
(additional side infos: Rails 4.0.1, rspec 3.0.0.beta1)

"Inspired" by CDub's comment, I took a look at the destroy action in Admin::OrganizationController, which looked like this:
def destroy
#organization.destroy
respond_to do |format|
format.html { redirect_to organizations_url } # <--- has to be admin_organizaions_url
format.json { head :no_content }
end
end
I didn't pay attention to the respond_to block at all.

Related

Update Test On Controller Breaks in Rails 4.1.12

I'm upgrading a Rails site from 4.0 to 4.1.12 and quite a few of my Rspec controller tests are now broken. For example this test broke with the upgrade:
it "update action should render edit template" do
#user = create(:user)
#user.name = "" # model requires name
#controller.stubs(:current_user).returns(#user)
put :update, id: #user
expect(response).to render_template(:edit)
end
I'm getting "No route matches {:action=>"show", :controller=>"accounts", :id=>nil} missing required keys: [:id]". It seems like the update_attributes method is ignoring my model validations all of a sudden.
Controller code:
def update
#user = current_user
if #user.update_attributes(params[:user])
redirect_to user_path(#user), :notice => "Your profile has been updated."
else
render :action => 'edit'
end
end
routes.rb
resources :users do
member do
get 'accounting'
end
collection do
post 'send_password'
end
end
I'm sure I've missed something in the upgrade process but I don't see anything in the docs that's telling me what that is.
So just to put down what I would do - rather than changing the #user object in the test you need to send in the changes you want to make to the user object as params of the request. This way the controller would receive it in the params[] hash - otherwise you aren't really testing what the controller method is doing.
it "with invalid data; update action should render edit template" do
#user = create(:user)
#controller.stubs(:current_user).returns(#user)
patch :update, id: #user, user: { name: '' }
expect(response).to render_template(:edit)
end

How to write test case for destroy method in rails?

#Destroy Action method
def destroy
Key.destroy(params[:id])
end
-------------------------------
#testcase for this
expect(delete :destroy ,{"id"=>"3"}).to change(Key, :count).by(-1)
It is showing Action view::template missing error can't I write test case for void action(returns nothing/render nothing) methods in rails.
Now i changed my method to render the json value.
def destroy
Key.destroy(params[:id])
respond_to do |format|
format.html {}
format.json { head :no_content }
end
end
Now my assertion for to run test case is:
it "should destroy" do
response=delete :destroy ,{"id"=>"3"}
expect(response).to have_http_status(204)
end
You can create a sample item with a Factory (for example Factory Girl) and then check if it exists or not. This is a sample destroy test (the query is for a Mongoid db instead, but you can get it.
In my case, my destroy method has a json response which can be checked as well (but I don't do it here).
let(:key_to_delete) {FactoryGirl.create(:key)}
it 'should destroy' do
delete :destroy, id: key_to_delete.id
expect(Key.where(id: key_to_delete.id).count).to eq(0)
end

ActionController::UnknownFormat: when using Rspec

I am creating a simple API to perform CRUD actions on contacts. :index, :show, :create and :update methods are working properly and they all pass their respective request rspec tests. The problem only arise in the :destroy method. The :destroy action looks like this:
class Api::V1::ContactsController < ApplicationController
def destroy
#contact = Contact.find(params[:id])
#contact.destroy
respond_to do |format|
format.json {render action: :index }
end
end
end
The spec to test DELETE request looks like this:
describe "DELETE /api/v1/contacts/:id" do
before(:each) do
#contact = FactoryGirl.create(:contact)
end
it "it should have a status code of 200" do
delete "/api/v1/contacts/#{#contact.id}"
expect(response.status).to eq(200)
end
it "It should delete a contact" do
expect{
delete "/api/v1/contacts/#{#contact.id}"
}.to change(Contact, :count).by(-1)
end
end
when i run the test i get this error message:
Failure/Error: delete "/api/v1/contacts/#{#contact.id}"
ActionController::UnknownFormat:
ActionController::UnknownFormat
# ./app/controllers/api/v1/contacts_controller.rb:67:in `destroy'
respond_to do |format| is line 67 in contacts_controller.rb
Try changing the format of your request to JSON, i.e. replace
delete "/api/v1/contacts/#{#contact.id}"
by
delete "/api/v1/contacts/#{#contact.id}.json"
that would allow the format logic to figure out that you want the reply rendered in JSON which it knows about.

Rspec redirect to testing

In my controller when an user creates a new post, he/she is redirected to the page that contains the newly created post. I'm wanting to create a test in rspec to cover this redirect but am having trouble with it. Specifically, I want to know what to write in the refirst_to argument. Here is the controller code below..
def create
#micropost = Micropost.new(params[:micropost])
respond_to do |format|
if #micropost.save
format.html {redirect_to #micropost}
else
format.html {render action: 'edit'}
end
end
end
Here is the rspec test...
before do
#params = FactoryGirl.build(:micropost)
end
it "redirects to index" do
#clearly #params.id doesn't work. its telling me instead of a redirect im getting a
#200
#response.should redirect_to(#params.id)
end
Assuming that #params will create a valid Micropost (otherwise .save will fail and you'll be rendering :edit)...
it "redirects to index on successful save" do
post :create, :micropost => #params.attributes
response.should be_redirect
response.should redirect_to(assigns[:micropost])
end
it "renders :edit on failed save" do
post :create, :micropost => {}
response.should render ... # i don't recall the exact syntax...
end

testing "create" method in ruby with rspec

I have written this controller code in Ruby on Rails
class PostsController < ApplicationController
before_filter :authenticate_user!
def index
#posts = Post.all(:order => "created_at DESC")
respond_to do |format|
format.html
end
end
def create
#post = Post.create(:message => params[:message])
respond_to do |format|
if #post.save
format.html { redirect_to posts_path }
format.js
else
flash[:notice] = "Message failed to save."
format.html { redirect_to posts_path }
end
end
end
end
and corresponding to this I have written the following test case :-
require 'spec_helper'
describe PostsController do
describe "GET 'index'" do
it "returns http success" do
get 'index'
response.should be_success
end
end
describe "#create" do
it "creates a successful mesaage post" do
#post = Post.create(message: "Message")
#post.should be_an_instance_of Post
end
end
end
I am getting failures on both. Please take a look on the code and help me figure out.
I suspect you are not logged in since you are using Devise?
Maybe you need to include the devise testhelpers:
describe PostsController do
include Devise::TestHelpers
before(:each) do
#user = User.create(...)
sign_in #user
end
#assertions go here
end
As Tigraine states, it appears as though you probably are not logged in (with Devise) when the tests get executed. However, showing the failures would help in narrowing down the problem further.
On top of that, the second test isn't really an integration test and I would probably prefer something like the following to test the same condition. There are two types of test you could do:
# inside 'describe "#create"'
let(:valid_params) { {'post' => {'title' => 'Test Post'} }
it 'creates a new Post' do
expect {
post :create, valid_params
}.to change(Post, :count).by(1)
end
# and / or
it 'assigns a new Post' do
post :create, valid_params
assigns(:post).should be_a(Post)
assigns(:post).should be_persisted
end
Don't forget to add this line into your spec_helper.rb
require "devise/test_helpers"
include Devise::TestHelpers
Nevertheless, here is link for Devise wiki - How to test Controllers where you can find more info about this approach. I recommend writing the before method without (:each), what I remember it sometimes causes problems.
before do
#user = FactoryGirl.create(:user)
sign_in #user
end
Can always use:
puts response.inspect
To see how your response looks like.

Resources