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::TestCaseinstead ofActionDispatch::IntegrationTestin new Rails versions can limit test coverage. - Not passing
params:hash correctly when testingpostorpatchrequests 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 / Assertion | Purpose |
|---|---|
| get :action or get url | Simulate 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 url | Simulate DELETE request |
| assert_response :success | Check HTTP 200 OK response |
| assert_redirected_to url | Check 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.