How to write test case for destroy method in rails? - ruby-on-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

Related

Rspec & Rails: Testing create action with invalid attributes

I am writing my first controller tests for Rails in Rspec. In testing the create action, I want to write a test that verifies that the 'new' template is rendered when the form is submitted with invalid attributes. In this case, that means a field is left blank.
I have found several examples that I have tried to follow verbatim. However, when using Rspec to trigger the create action, it seems like ActiveRecord actually tries to create that record which, due to validations, fails. Thus, my test fails before I even get to test the redirect function. This does not seem to be an issue for the people writing the tutorials or StackOverflow answers.
What is the best way to test the create action in a controller, given invalid attributes?
Rails 4.0.0, Ruby 2.0.0, Rspec 3.0.0.beta2
order_items_controller_spec
describe "POST create" do
context "with invalid attributes" do
it "re-renders the new method" do
post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
expect( response ).to render_template :new
end
end
end
order_items_controller
def create
#order_item = OrderItem.new(order_item_params)
respond_to do |format|
if #order_item.save!
format.html { redirect_to cart_path(#order_item), notice: 'Your trip has been added to your cart.' }
format.json { render action: 'show', status: :created, location: #order_item }
else
format.html { redirect_to new_order_item_path, notice: 'We were unable to customize your trip.' }
format.json { render json: #order_item.errors, status: :unprocessable_entity }
end
end
end
rspec error message:
OrderItemsController POST create with invalid attributes re-renders the new method
Failure/Error: post :create, order_item: FactoryGirl.attributes_for(:order_item, :buyer_id => nil)
ActiveRecord::RecordInvalid:
Validation failed: Buyer can't be blank
# ./app/controllers/order_items_controller.rb:30:in `block in create'
# ./app/controllers/order_items_controller.rb:29:in `create'
# ./spec/controllers/order_items_controller_spec.rb:43:in `block (4 levels) in <top (required)>'
Thanks in advance.
Your test looks good; it's actually your code which is failing to work as you expect when the save fails. When you say "ActiveRecord actually tries to create that record which, due to validations, fails", that's exactly what you want your test to be doing, because you are trying to test what happens if the validation fails.
In your controller you are saving the record with save!. This will cause an error be raised if the save fails, which is why you immediately see a failure in rspec rather than it going on to the new view.
Instead you want to use save (without the bang). This will return true/false depending on the save success so you can use it in a condition.
Your controller code should be:
def create
#order_item = OrderItem.new(order_item_params)
respond_to do |format|
if #order_item.save ### ! removed
...
Don't use 'save!' ... you should be using 'save' which will return false if not valid.

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.

Testing Rails nested controllers

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.

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

Rails - Functional testing of redirect_to(request.referer)

Maybe I just missing the forest for the trees again, but I can't seem to figure out a way to write a functional test that tests a :destroy action that redirects to request.referer.
Code is:
def destroy
#step = Step.find(params[:id])
#step.destroy
respond_to do |format|
format.html { redirect_to(request.referer) }
format.xml { head :ok }
end
end
Failing test is:
test "should destroy step" do
assert_difference('Step.count', -1) do
delete :destroy, :id => #step.to_param
end
assert_redirected_to request.referer
end
Having no luck using:
redirect_to(:back)
... as well.
Got it.
Passing test is:
test "should destroy step" do
assert_difference('Step.count', -1) do
#request.env['HTTP_REFERER'] = 'http://test.com/steps/1'
delete :destroy, :id => #step.to_param
end
assert_redirected_to #request.env['HTTP_REFERER']
end
Thanks to help from: How do I set HTTP_REFERER when testing in Rails?
you write an integration test and use one of delete_via_redirect which should follow the redirect. You may also have to set the the HTTP_REFERER header - see guide.rubyonrails.org

Resources