first posting on this helpful community, but have been using it since the start of my programming journey. I'm new to rails and have trouble writing tests. So far, I've been trying to write a controller test based on the Authlogic perishable token guide .
But during the test, it keeps getting stuck on the line
#controller
#user = User.find_using_perishable_token(params[:activation_code], 1.week) || (redirect_to new_user_session_url and return)
and here's the line in the test that gets into trouble:
#test
User.any_instance.stub(:find_using_perishable_token) {mock_model(User, stubs(:active => true)) }
get :create, :activation_code => 'valid'
response.should render_template 'new'
response.code.should == "200"
#the test response is 302, not 200
response.should redirect_to("/")
#the test shows the path as user_sessions/new,
#meaning it didn't pass the condition in the controller with the find_using_pt method
Heres the test output:
Failure/Error: response.should render_template 'new' expecting <"new"> but rendering with <"">
# ./spec/controllers/activations_controller_spec.rb:18:in `block (3 levels) in <top (required)>'
After reading one of the posted answers ,it seems that I'm not creating the stub/mock correctly and that's why it keeps getting the redirect_to (302) rather than continuing with the test. (the find_using_pt is a method from Authlogic). Hence, the trouble is with the redirect_to line as it never continues with the controller/page render
Any advice would be greatly appreciated. Thanks.
Related
I'm using FactoryGirl and Rspec for my test framework. I have a model that has a validates_presence_of validation on it. The basic Rspec framework includes a test:
describe "with invalid params" do
it "assigns a newly created but unsaved disease as #disease" do
# Trigger the behavior that occurs when invalid params are submitted
Disease.any_instance.stub(:save).and_return(false)
post :create, :disease => {}
assigns(:disease).should be_a_new(Disease)
end
end
Edit:
diseases_controller.rb
# POST /diseases
# POST /diseases.xml
def create
#disease = Disease.new(disease_params)
respond_to do |format|
if #disease.save
format.html { redirect_to(#disease, :notice => 'Disease was successfully created.') }
format.xml { render :xml => #disease, :status => :created, :location => #disease }
else
format.html { render :action => "new" }
format.xml { render :xml => #disease.errors, :status => :unprocessable_entity }
end
end
end
private
def disease_params
params.require(:disease).permit(:name, :omim_id, :description)
end
This test doesn't work with how my application works. Rather than returning a new disease on an incorrect post, it returns an error:
Required parameter missing: disease
Question #1: I don't know how to look at what is being returned with Rspec does the post. The response object doesn't appear to be created in this case? Printing assigns(:disease) doesn't appear to contain anything. I got the error message I posted earlier by submitting a cURL post to the correct URL with empty data (which is what the rspect post should be doing), but I don't know how to get the information of what Rspec is receiving back from the post statement.
Question #2: How do I properly test the response that should be occurring - that it receives an error message saying that a required parameter is missing?
edit:
So my controller seems to indicate that it should render a new disease, but the test fails. If I attempt to submit a disease missing the required parameter on the website, then it does a flash notice that says "Name can't be blank". I'm not sure how to test that in rspec.
edit #2:
Included the code above. disease_params is defined at the bottom of the controller in accordance with recommendations for using the strong_parameters gem.
Thanks!
To answer Question 1 ("I don't know how to look at what is being returned with Rspec does the post")... You can use "puts" statements within your spec (i.e. within the it block). For instance, you can try something like this:
describe "with invalid params" do
it "assigns a newly created but unsaved disease as #disease" do
# Trigger the behavior that occurs when invalid params are submitted
Disease.any_instance.stub(:save).and_return(false)
post :create, :disease => {}
puts :disease
assigns(:disease).should be_a_new(Disease)
end
end
It's a valuable debugging tool. The output will be in the .s and Fs in the terminal when RSpec is running.
For Question 2, I'm not quite sure what you're looking for, but I don't know that you need to (or should) test that the invalid disease is assigned as #disease. I tend to pattern controller specs in the following style (taken from Everyday Rails Testing with RSpec which is where I learned how to write controller specs).
POST create spec example:
context "with invalid attributes" do
it "does not save the new contact" do
expect{
post :create, contact: Factory.attributes_for(:invalid_contact)
}.to_not change(Contact,:count)
end
it "re-renders the new method" do
post :create, contact: Factory.attributes_for(:invalid_contact)
response.should render_template :new
end
end
...
You may have a reason for more thoroughly testing the controller method that I don't know about. In that case, kindly disregard my answer to Question 2 and hopefully my other answer is useful!
I'm running this test on rspec...
it 'get email is successful' do
get :email
response.should be_success
response.should render_template('email')
end
Where the controller code looks like this..
def email
respond_to do |format|
format.js
end
end
On my terminal I'm returning with....
3) PostsController checking to see if response for post email is successful
Failure/Error: response.should be_success
expected success? to return true, got false
# ./spec/controllers/posts_controller_spec.rb:116:in `block (3 levels) in <top
(required)>'
What am I missing here to make the test work? It has to be something obvious. My view file is titled email.js.erb. This action is meant for an AJAX call.
try:
xhr :get, :email
your request seems not to take into account the expected response type. In Rspec, this is the way to do it if you want to simulate AJAX (XHR) requests.
Your controller is structured to return anything only for JS requests and you are requesting HTML response in your tests. You should have
get :email.js
in your spec.
I am writing some specs and the following is failing but the page /menus/1 is loading fine in a browser. This is a port of a php app and is first time I've used RSpec. Any thoughts as to why it might not be working.
The error is:
1) MenusController GET 'show' should be succesful
Failure/Error: get :show, :id => 1
ActiveRecord::RecordNotFound:
Couldn't find MenuHeader with id=1
# ./app/controllers/menus_controller.rb:18:in `show'
# ./spec/controllers/menus_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
but that specific MenuHeader does exist based upon all normal criteria (console, mysql, browser). I'm 99% sure I have a mistake in my spec:
require 'spec_helper'
describe MenusController do
describe "GET 'show'" do
it "should be succesful" do
get :show, :id => 1
response.should be_success
end
end
end
here is the menus_controller.rb
def show
#menu_header_data=MenuHeader.find(params[:id])
respond_to do |format|
format.html # show.html.erb
# format.json { render json: #menu } to do
end
end
thx
When testing a controller with Rspec or TestUnit I would use a Factory or Fixture to pass the id rather than setting up a test database with data. It's better to test with something like:
Using FactoryGirl (My Recommendation but everyone has their own tastes):
describe MenusController do
describe "GET 'show'" do
it "should be succesful" do
get :show, :id => Factory(:menu).id
response.should be_success
end
end
end
The test is mainly just to make sure the controller responds properly when provided valid data, and using Factories or Fixtures is much less brittle. It will become a pain to maintain your test suite if it's based on hard data like fixtures or a db backup, and that could ultimately lead to you giving up on Test Driven Development rather than embracing it.
I am currently using rspec with cancan. I realized that littering permission control test cases all over my controllers spec files is extremely messy. Basically, almost every controller spec files of mine has something along the lines:
describe "failure" do
it { get :new }
it { get :edit, :id => #deal }
it { get :update, :id => #deal }
it { get :destroy, :id => #deal }
after(:each) do
response.should_not be_success
response.should redirect_to(root_path)
flash[:error].should == "Permission denied."
end
end
end
I have 4 roles in my system and this definitely makes organization a much more difficult task.
Since all of these tests are related to permission control/ACL, I tried putting them all in one file rspec/models/ability_spec.rb
right now, my ability_spec looks like this:
describe "cancan" do
it "failure" do
#ability.should_not be_able_to(:all, Factory(:purchase))
#ability.should_not be_able_to(:all, Factory(:user))
#ability.should_not be_able_to(:all, Visit)
end
end
I am getting the following error:
6) Ability consumers deals failure
Failure/Error: it { get :destroy, :id => #deal }
NoMethodError:
undefined method `get' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1::Nested_2::Nested_2:0x007fd73209a270>
# ./spec/models/ability_spec.rb:46:in `block (5 levels) in <top (required)>'
I know I am not supposed to put controller get/post in this file. Is there a way to do this for the sake of simplifying testing for my permission related tests?
Take a look at RSpec's shared examples and see if you can pull anything out into a shared example group:
http://relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples
I have a user_controller_spec.rb that is failing, and I'm not sure why.
require 'spec_helper'
describe UsersController do
describe "GET 'index'" do
it "should be successful" do
get 'index'
response.should be_success
end
end
end
When I run rspec it says:
Failures:
1) UsersController GET 'index' should be successful
Failure/Error: response.should be_success
expected success? to return true, got false
# ./spec/controllers/users_controller_spec.rb:8
Finished in 0.17047 seconds
1 example, 1 failure
Going to the /home/ page in the browser works fine.
Is there a way to get a more detailed reason why it is failing?
Note:
This is rails3, and I am using rspec.
I also have the capybara gem, and searching my solution shows the only reference to capybara is in my gem and gem.lock file.
You can try outputting the response body to see what the message is. Could be anything from the user you're logged in as not having the correct permissions (or visiting a page anonymously that you must be logged in to see) to a strange view error in test environment.
get 'index'
puts response.body.inspect
puts response.status.inspect
...
response.should be_success
response.body will contain the HTML output of the response, so you should be able to tell why it's not a success (hopefully it will have a stack trace or be a redirect or something). Also keep in mind redirecting is not "success". If I remember correctly be_success makes sure the HTTP status code is one of the 200s, redirects are usually 302 or 304 so do not count. If a redirect is intended, try response.should be_redirect.
It could be that you do not just render the page, but redirect. To check on what may be wrong, i would do in my spec something like :
response.should == 1
in order to see what the actual response is. This would give you a good clue on what is happening.