This blog is part of our Rails 5 series.

In Rails 5, controller tests have undergone some major changes. In this blog post, we will walk through some of those changes.

ActionController::TestCase is deprecated

In Rails 5, controller tests are generated with superclass ActionDispatch::IntegrationTest instead of ActionController::TestCase which is deprecated . It will be moved into a separate gem in Rails 5.1 .

Rails 5 will use ActionDispatch::IntegrationTest by default for generating scaffolds as well controller tests stubs.

Use URL instead of action name with request methods in Rails 5

In Rails 4.x, we pass controller action as shown below.

class ProductsControllerTest < ActionController :: TestCase def test_index_response get :index assert_response :success end end

But in Rails 5, controller tests expect to receive URL instead of action. Otherwise test will throw exception URI::InvalidURIError: bad URI .

class ProductsControllerTest < ActionDispatch :: IntegrationTest def test_index get products_url assert_response :success end end

If we are upgrading an older Rails 4.x app to Rails 5, which have test cases with superclass ActionController::TestCase , then they will continue to work as it is without requiring to change anything from above.

Deprecation of assigns and assert_template in controller tests

In Rails 4.x, we can test instance variables assigned in a controller action and which template a particular controller action renders using assigns and assert_template methods.

class ProductsControllerTest < ActionController :: TestCase def test_index_template_rendered get :index assert_template :index assert_equal Product . all , assigns ( :products ) end end

But in Rails 5, calling assert_template or assigns will throw an exception.

class ProductsControllerTest < ActionDispatch :: IntegrationTest def test_index_template_rendered get products_url assert_template :index assert_equal Product . all , assigns ( :products ) end end # Throws exception NoMethodError : assert_template has been extracted to a gem . To continue using it , add `gem 'rails-controller-testing'` to your Gemfile .

These two methods have now been removed from the core and moved to a separate gem rails-controller-testing. If we still want to use assert_template and assigns , then we can do this by adding this gem in our applications.

Reasons for removing assigns and assert_template

The idea behind the removal of these methods is that instance variables and which template is rendered in a controller action are internals of a controller, and controller tests should not care about them.

According to Rails team, controller tests should be more concerned about what is the result of that controller action like what cookies are set, or what HTTP code is set rather than testing of the internals of the controller. So, these methods are removed from the core.

Use of Keywords arguments in HTTP request methods in Rails 5

In Rails 4.x, we pass various arguments like params, flash messages and session variables to request method directly.

class ProductsControllerTest < ActionController :: TestCase def test_show get :show , { id: user . id }, { notice: 'Welcome' }, { admin: user . admin? } assert_response :success end end

Where { id: user.id } are params, { notice: 'Welcome' } is flash and { admin: user.admin? } is session.

This becomes confusing sometimes, as it is not clear which argument belongs to which part.

Now in Rails 5, request methods accept only keyword arguments.

class ProductsControllerTest < ActionDispatch :: IntegrationTest def test_create post product_url , params: { product: { name: "FIFA" } } assert_response :success end end

This makes it easier to understand what arguments are being passed.

When we pass arguments without keywords arguments, then Rails logs a deprecation warning.