I'm need to test my controller with minitest.
I've tried:
describe 'CommentsController' do
it "should get index" do
get :index
assert_response :success
end
end
and
class CommentsControllerTest < MiniTest::Unit::TestCase
def test_should_get_index
get :index
assert_response :success
end
end
but I have "undefined method `get'" error
You should add the minitest-rails gem, following the steps outlined in the documentation. Then your tests should look like this:
require "minitest_helper"
describe CommentsController do
it "should get index" do
get :index
assert_response :success
end
end
Or, look like this:
require "minitest_helper"
class CommentsControllerTest < MiniTest::Rails::ActionController::TestCase
test "should get index" do
get :index
assert_response :success
end
end
Related
My controller and my test file are bellow.
controllers/reports_controller.rb:
def index
#reports = Report.all
end
specs/controllers/reports_controller_spec.rb:
RSpec.describe ReportsController, type: :controller do
let(:test_report) {
2.times.map {
create(:report, student: create(:student), report_options_attributes: [
{option: create(:option), note: "ole" }
])
}
}
describe "GET #index" do
before(:each) do
get :index
end
it "should be success" do
expect(response).to be_success
end
it "should render index template" do
expect(response).to render_template(:index)
end
it "should load all reports" do
expect(assigns(:report)).to match_array test_report
end
end
The last test is not working, but it should work. What is wrong with it?
index test is empty..you need to assert something to pass.
can you add.. assert_response :success in index function.
Your var is different from the controller. Use reports instead of report like this:
it "should load all reports" do
expect(assigns(:reports)).to match_array test_report
end
It should work.
I am working through railstutorial.org and in our first test suite we setup an instance variable in a setup method.
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
def setup
#base_title = "Ruby on Rails Tutorial Sample App"
end
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Home | #{#base_title}"
end
test "should get help" do
get static_pages_help_url
assert_response :success
assert_select "title", "Help | #{#base_title}"
end
test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title", "About | #{#base_title}"
end
end
Why do we do this instead of just defining it straight up as an instance variable?
You are defining it as an instance variable. When the test is run the class (StaticPagesControllerTest) is instantiated and the setup function called on that instance, not on the class. If you tried to do the following instead it would define a class level instance variable not accessible from instances:
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
#base_title = "Ruby on Rails Tutorial Sample App"
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Home | #{#base_title}" # XXX not defined on instance
end
...
See this page for one explanation of the difference.
You could use a class variable (##base_title) but that might cause surprising consequences later, e.g. if you wanted to subclass the test.
Here's a quick demonstration:
class First
#a = 'hoge'
##b = 'hoge'
def initialize
#c = 'hoge'
end
def give_me_a
#a
end
def give_me_b
##b
end
def give_me_c
#c
end
end
f = First.new
# => #<First:0x007fb81607fcd0>
f.give_me_a
# => nil
f.give_me_b
# => "hoge"
f.give_me_c
# => "hoge"
I've got a filter which ensures that only super admins can access a particular action:
before_action :require_super_admin
def index; end
In my controller tests I've got:
test "should let super admin access index" do
login_super_admin
get :index
assert_response :success
end
test "should NOT let normal admin access index" do
login_normal_admin
get :index
assert_response :redirect
end
test "should NOT let user access index" do
login_user
get :index
assert_response :redirect
end
test "should NOT let guest access index" do
login_guest
get :index
assert_response :redirect
end
That's four tests to ensure that only a super admin can access the index. Is there a better way of testing this? Does anyone else ever find themselves doing this sort of thing? I run into it every time I build a rails app.
You can create shared examples
shared_example "allow super admins" do |actions|
actions.each do |action|
it "should let super admin access #{action}" do
login_super_admin
get action.to_sym
assert_response :success
end
end
end
shared example "deny non super admins" do |actions, users|
actions.each do |action|
users.each do |user|
it "should let not let #{user} access #{action}" do
send("login_#{user}")
get action.to_sym
assert_response :redirect
end
end
end
end
And in your tests that need authorization check, you can do
it_behaves_like "allow super admins", ["index"]
it behaves_like "deny non super admins", ["index"], ["normal_admin", "user", "guest"]
PS: I haven't tested this. This is just to give you an idea
My solution:
# Gemfile
gem 'shoulda-context'
# In test_helper.rb
class ActiveSupport::TestCase
def make_sure_authorization_kicks_in
assert_redirected_to root_url
assert_equal "You are not authorized to perform this action.", flash[:error]
end
end
# In controller tests
context "NOT Super Admin" do
# saves a lot of typing
teardown { make_sure_pundit_kicks_in }
context "just NORMAL ADMIN" do
setup { login_normal_admin }
should("NOT get index"){ get :index }
should("NOT get new"){ get :new }
end
context "just normal USER" do
setup { login_user }
should("NOT get index"){ get :index }
should("NOT get new"){ get :new }
end
end
This is much easier to manage.
I'm writing tests with rspec for my application controller in my rails app (written in Rails 4) and I'm running into a problem where it doesn't recognize the route for the HTTP request I'm sending. I know there's a way to do this using MyApp::Application.routes but I'm not able to get it working.
#application_controller_spec.rb
require 'spec_helper'
class TestController < ApplicationController
def index; end
end
describe TestController do
before(:each) do
#first_user = FactoryGirl.create(:user)
# this is to ensure that all before_filters are run
controller.stub(:first_time_user)
controller.stub(:current_user)
end
describe 'first_time_user' do
before(:each) do
controller.unstub(:first_time_user)
end
context 'is in db' do
before(:each) do
#user = FactoryGirl.create(:user)
controller.stub(:current_user).and_return(#user)
end
it 'should not redirect' do
get :index
response.should_not be_redirect
end
end
context 'is not in db' do
context 'session[:cas_user] does not exist' do
it 'should return nil' do
get :index
expect(assigns(:current_user)).to eq(nil)
end
end
it "should redirect_to new_user_path" do
controller.stub(:current_user, redirect: true).and_return(nil)
get :index
response.should be_redirect
end
end
end
The error I'm getting right now is
No route matches {:action=>"index", :controller=>"test"}
I would add the test#index route to config/routes.rb, but it doesn't recognize the Test Controller, so I want to do something like
MyApp::Application.routes.append do
controller :test do
get 'test/index' => :index
end
end
but I'm not sure where to add this or if this even works in rspec. Any help would be great!
If you are trying to test your ApplicationController, see this RSpec documentation about it. You will need to define methods like index inside the test, but it works well.
I am attempting to create a RSpec controller test for a namespaced controller, but rspec doesn't seem able to detect the nesting and generate the proper path for the post :create action.
This is my spec code:
# for: /app/controllers/admin/crm/report_adjustments_controller.rb
require 'spec_helper'
describe Admin::Crm::ReportAdjustmentsController do
render_views
before(:each) do
signin
end
describe "GET 'index'" do
it "returns http success" do
get :index
response.should be_success
end
end
describe "POST 'create'" do
it "creates with right parameters" do
expect {
post :create, report_adjustment: {distributor_id: #ole_distributor.id, amount: "30.0", date: Date.today }
}.to change(Crm::ReportAdjustment, :count).by(1)
response.should be_success
end
end
end
# routes.rb
namespace :admin do
namespace :crm do
resources :report_adjustments
end
end
For this code, the get :index works just fine, but when post :create is called, the following error is generated: undefined method 'crm_report_adjustment_url'
Why would RSpec be smart enough to figure things out with get :index, but not with post :create? How do I get RSpec to properly load the right route, which is admin_crm_report_adjustments_url?
Thanks in advance.
Try posting to the url instead:
post admin_crm_report_adjustments_url
# or
post "/admin/crm/report_adjustments"