Changes to test controllers in Rails 5

Abhishek Jain

Abhishek Jain

April 19, 2016

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 (Link is not available) . 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 (Link is not available). 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.


class ProductsControllerTest < ActionDispatch::IntegrationTest

  def test_create
    post product_url, { product: { name: "FIFA" } }
    assert_response :success
  end
end

DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept
only the following keyword arguments in future Rails versions:
params, headers, env, xhr

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.