---
title: "Changes to test controllers in Rails 5"
description:
  "Deprecation of assigns and assert_template in controller tests and usage of
  keyword arguments in HTTP methods"
canonical_url: "https://www.bigbinary.com/blog/changes-to-test-controllers-in-rails-5"
markdown_url: "https://www.bigbinary.com/blog/changes-to-test-controllers-in-rails-5.md"
---

# Changes to test controllers in Rails 5

Deprecation of assigns and assert_template in controller tests and usage of
keyword arguments in HTTP methods

- Author: Abhishek Jain
- Published: April 19, 2016
- Categories: Rails 5, Rails

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](https://github.com/rails/rails/pull/22569).

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

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

```ruby
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`.

```ruby

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.

```ruby

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.

```ruby

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](https://github.com/rails/rails/pull/20138) from the core and moved to
a separate gem
[rails-controller-testing](https://github.com/rails/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.

```ruby

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](https://github.com/rails/rails/pull/18323/).

```ruby

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.

```ruby

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

```

## Links

- [Human page](https://www.bigbinary.com/blog/changes-to-test-controllers-in-rails-5)
