Simple example that by all accounts should work:
require 'test_helper'
class FoosController < ApplicationController
def index
render plain: 'something'
end
end
class UsersControllerTest < ActionDispatch::IntegrationTest
def test_some_routing
with_routing do |set|
set.draw do
get '/foos' => 'foos#index'
end
get '/foos'
assert_equal 200, response.status
end
end
end
Instead I'm getting: ActionController::RoutingError: No route matches [GET] "/foos"
What am I doing wrong? This is latest Rails 4.1 btw.
For those who come here seeking a solution to test their controller concerns in isolation (like I did), it may pay to use setup and teardown blocks instead of littering your code with with_routing blocks:
require 'test_helper'
class ConcernedController < ApplicationController
include Concern
def action
render plain: "response", status: :ok
end
end
class ConcernTest < ActionDispatch::IntegrationTest
setup do
#controller = ConcernedController.new
Rails.application.routes.draw do
get "/action" => "concerned#action"
post "/action" => "concerned#action"
end
end
teardown do
Rails.application.reload_routes!
end
test "concern method" do
post "/action"
# Test what the concern does
assert_response :ok
assert_equal "Response", response.body
end
end
Tested against Rails 5.0.2.
Ok, so I'm answering my own questions again. Problem is that with_routing doesn't work at all inside integration tests. Oversight or something, not sure. It only works for controller tests. So here's the work around:
class ActionDispatch::IntegrationTest
def with_routing(&block)
yield ComfortableMexicanSofa::Application.routes
ensure
ComfortableMexicanSofa::Application.routes_reloader.reload!
end
end
Basically you will redefine your application routes within that block and then reload them back from the routes.rb file.
-- edited --
We can have a block with new routes by defining a new method like:
def with_foo_route
Rails.application.routes.draw do
get 'foo' => 'foo#index'
end
yield
Rails.application.routes_reloader.reload!
end
And then execute a get requests to this new route by:
with_foo_route do
get '/foo'
assert_equal 200, status
end
Related
I try to test my controller concerns using minitest-rails and combining this techniques:
http://ridingtheclutch.com/post/55701769414/testing-controller-concerns-in-rails.
Anonymous controller in Minitest w/ Rails
And i get "no route matches error":
ActionController::UrlGenerationError: No route matches {:action=>"index", :controller=>"fake"}
require "test_helper"
require "warden_mock"
class FakeController < ApplicationController
attr_accessor :request
def initialize(method_name=nil, &method_body)
include MyConcern # method redirect_to_404 placed here
#request = OpenStruct.new # mockup request
#request.env = {}
#request.env['warden'] = WardenMock.new # mockup warden
if method_name and block_given? # dynamically define action for concern methods testing
self.class.send(:define_method, method_name, method_body)
test_routes = Proc.new do
resources :fake
end
Rails.application.routes.eval_block(test_routes)
end
end
end
describe FakeController do # just very simple test
context "just redirect_to_404" do
it "it must redirect to /404" do
#controller = FakeController.new(:index) { redirect_to_404 }
get :index
assert_redirected_to '/404'
end
end
end
I have rails 4.1.5 and minitest 5.4.0
Probably too late for the OP, but I've done it in this way:
require 'test_helper'
class SolrSearchParamsFakeController < ApplicationController
include SolrSearchParams # this is my controller's concern to test
def index
# The concern modify some of the parameters, so I'm saving them in a
# variable for future test inspection, so YMMV here.
#params = params
render nothing: true
end
end
Rails.application.routes.draw do
# Adding a route to the fake controller manually
get 'index' => 'solr_search_params_fake#index'
end
class SolrSearchParamsFakeControllerTest < ActionController::TestCase
def test_index
get :index, search: 'asdf wert'
# finally checking if the parameters were modified as I expect
params = assigns(:params)
assert_equal params[:original_search], 'asdf wert'
end
end
Update
Sorry, but actually this is messing up all my tests that involve route access in some way, as with Rails.application.routes.draw I'm rewriting all the routes for tests and leaving just that solr_search_params_fake#index route.
Not sure how to add instead of rewriting.... a fix would be adding directly to config/routes.rb my test routes with an if Rails.env.test? condition? (yeah, it's a crappy solution, but I'll leave this here in case someone find a better way to do this).
I'm using minitest in Rails to do testing, but I'm running into a problem that I hope a more seasoned tester can help me out with because I've tried looking everywhere for the answer, but it doesn't seem that anyone has run into this problem or if they have, they opted for an integration test.
Let's say I have a controller called Foo and action in it called bar. So the foo_controller.rb file looks like this:
class FooController < ApplicationController
def bar
render 'bar', :layout => 'application'
end
end
The thing is that I don't want people to access the "foo/bar" route directly. So I have a route that is get 'baz' => 'foo#bar'.
Now I want to test the FooController:
require 'minitest_helper'
class FooControllerTest < ActionController::TestCase
def test_should_get_index
get '/baz'
end
end
But the test results in an error that No route matches {:controller=>"foo", :action=>"/baz"}. How do I specify the controller for the GET request?
Sorry if this is a dumb question. It's been very hard for me to find the answer.
Try to test thus:
With Rails 3:
require 'minitest_helper'
class FooControllerTest < ActionController::TestCase
def test_should_get_index
assert_routing "/baz", :controller => "foo", :action => "bar"
end
end
With Rails 4:
require "test_helper"
class FooControllerTest < ActionDispatch::IntegrationTest
def test_should_get_index
assert_generates "/baz", :controller => "foo", :action => "bar"
end
end
I keep getting
#controller is nil: make sure you set it in your test's setup method.
When I run my tests. Any idea what this means?
when you inherit from ActionController::TestCase it infers the controller name from the test name if they do not match you have to use the setup part of test to set it.
So if you have
class PostsControllerTest < ActionController::TestCase
def test_index
#assert something
end
end
Then #controller is auto instantiated to PostsController, however, if this were not the case and you had a different name you would need a setup as such
class SomeTest < ActionController::TestCase
def setup
#controller = PostController.new
end
end
I was in the process of upgrading to rspec 3 from the beta version on rails 4 and ran into this error. The problem turned out to be that our Controller spec describe statements used symbols instead of strings. Rspec was attempting to instantiate the symbol as the controller but they were in fact 'actions'.
#trys to set #controller = Index.new
describe SomeController do
describe :index do
before do
get :index, format: :json
end
it { expect(response).to be_success}
end
end
#works
describe SomeController do
describe 'index' do
before do
get :index, format: :json
end
it { expect(response).to be_success}
end
end
ErsatzRyan answer is correct, however there is a small typo. Instead of
#controller = PostsController
it should be
#controller = PostsController.new
otherwise you get an error: undefined method `response_body='
Check whether you are ending the do and end properly.
RSpec.describe LeadsController, type: :controller do
# All tests should come here
end
If the names match, and the #controller variable is still nil, try checking for errors in the controller instantiation. For me I had a controller initialize method that had a bug in it. For some reason the controller was just nil in the test, rather than throwing an error when it wasn't instantiated.
Or, you can simply do this:
RSpec.describe PostsControllerTest, :type => :controller do
# ...
end
In Rails 6 looks like it is like this:
tests PostController
https://www.rubydoc.info/docs/rails/4.1.7/ActionController/TestCase#label-Controller+is+automatically+inferred
I encountered this error because I surrounded the controller name in quotes.
# broken
RSpec.describe 'RegistrationsController', type: :controller do
...
end
# works
RSpec.describe RegistrationsController, type: :controller do
...
end
I'm using Shoulda, Mocha, and Test::Unit for testing. I have the following controller and test:
class FoosController < ApplicationController
caches_action :show
def show
#foo = requested_foo
end
private
def requested_foo
Foo.find(params[:id])
end
end
class FoosCachingTest < ActionController::IntegrationTest
def setup
#foo = Foo.first
#session = open_session
end
context 'FoosController#show' do
setup do
#session.get('/foos/1')
end
before_should 'not fetch the Foo from the database' do
FoosController.any_instance.expects(:requested_foo).never
end
before_should 'fetch the Foo from the database' do
FoosController.any_instance.expects(:requested_foo).once.returns(#foo)
end
end
end
How is it that both of those tests could pass? I am not explicitly expiring my mocks at any point. Are Mohca and Shoulda known to interact poorly in this regard?
Aha! The problem is that the expectations do indeed fail but the errors they throw are swallowed up by the controller's error handling. Testing that the action renders properly makes the proper test fail.
I have an application that detects the subdomain on a request and sets the result to a variable.
e.g.
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
How can I test this with Test::Unit / Shoulda? I don't see a way of getting into ApplicationController and seeing what's set...
The assigns method should allow you to query the value of #selected_trust. To assert that its value equals "test" as follows:
assert_equal 'test', assigns('selected_trust')
Given a controller foo_controller.rb
class FooController < ApplicationController
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
def index
render :text => 'Hello world'
end
end
one might write a functional test as follows in foo_controller_test.rb:
class FooControllerTest < ActionController::TestCase
def test_index
get :index
assert #response.body.include?('Hello world')
assert_equal 'test', assigns('selected_trust')
end
end
Related to comment: note that the filter can be placed in ApplicationController and then any derived controller will also inherit this filter behaviour:
class ApplicationController < ActionController::Base
before_filter :get_trust_from_subdomain
def get_trust_from_subdomain
#selected_trust = "test"
end
end
class FooController < ApplicationController
# get_trust_from_subdomain filter will run before this action.
def index
render :text => 'Hello world'
end
end
ApplicationController is global, have you considered writing a Rack Middleware instead? Way easier to test.
I've opted for this in another controller in the application:
require 'test_helper'
class HomeControllerTest < ActionController::TestCase
fast_context 'a GET to :index' do
setup do
Factory :trust
get :index
end
should respond_with :success
should 'set the trust correctly' do
assert_equal 'test', assigns(:selected_trust)
end
end
end