0
0
RailsHow-ToBeginner · 4 min read

How to Test Controller in Rails: Simple Guide with Examples

To test a controller in Rails, use ActionDispatch::IntegrationTest or ActionController::TestCase with methods like get, post, patch, and delete to simulate requests. Then, assert the response status, rendered templates, or assigned variables to verify controller behavior.
📐

Syntax

Rails controller tests simulate HTTP requests to controller actions and check responses. Use methods like get :action_name to call an action. Then use assertions like assert_response :success to check the HTTP status or assert_template to verify the rendered view.

In modern Rails, integration tests with get url are preferred for full request cycles.

ruby
class ArticlesControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get articles_url
    assert_response :success
    assert_select 'h1', 'Articles'
  end
end
💻

Example

This example shows a simple test for the index action of an Articles controller. It sends a GET request to the index URL, checks for a successful response, and verifies that the page contains an h1 heading with the text 'Articles'.

ruby
require 'test_helper'

class ArticlesControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get articles_url
    assert_response :success
    assert_select 'h1', 'Articles'
  end

  test "should create article" do
    assert_difference('Article.count') do
      post articles_url, params: { article: { title: 'New Article', body: 'Content here' } }
    end
    assert_redirected_to article_url(Article.last)
  end
end
Output
Run options: --seed 12345 # Running: .. Finished in 0.12345s, 16.19 runs/s, 32.38 assertions/s. 2 runs, 4 assertions, 0 failures, 0 errors, 0 skips
⚠️

Common Pitfalls

  • Using ActionController::TestCase instead of ActionDispatch::IntegrationTest in new Rails versions can limit test coverage.
  • Not passing params: hash correctly when testing post or patch requests causes errors.
  • Forgetting to assert the response or redirect leads to tests that pass without verifying behavior.
  • Testing controller internals like instance variables instead of response or behavior is discouraged.
ruby
class WrongControllerTest < ActionController::TestCase
  test "wrong post without params" do
    post :create
    assert_response :redirect
  end
end

# Correct way:
class RightControllerTest < ActionDispatch::IntegrationTest
  test "correct post with params" do
    post articles_url, params: { article: { title: 'Test', body: 'Body' } }
    assert_redirected_to article_url(Article.last)
  end
end
📊

Quick Reference

Here is a quick summary of common test methods and assertions for Rails controller tests:

Method / AssertionPurpose
get :action or get urlSimulate GET request to controller action or URL
post :action or post url, params:Simulate POST request with parameters
patch :action or patch url, params:Simulate PATCH request with parameters
delete :action or delete urlSimulate DELETE request
assert_response :successCheck HTTP 200 OK response
assert_redirected_to urlCheck redirection to a URL
assert_select 'selector', 'text'Check HTML content in response
assert_difference('Model.count')Check that a record count changes

Key Takeaways

Use ActionDispatch::IntegrationTest with HTTP methods to test controller actions fully.
Always pass params as a hash when testing POST, PATCH, or DELETE requests.
Assert response status and content to verify controller behavior.
Avoid testing controller internals; focus on request and response.
Use assert_select to check rendered HTML elements in the response.