Controller tests in Rails are automated tests in which we simulate HTTP requests to check whether our controllers process and respond to them correctly. We will write at least one controller test for every controller action.
In this part, we will add a controller test for the index
action of the LimericksController
controller class. Our aim is to confirm that if our app receives an HTTP GET request with the URL for the limericks index page, the app will process the request without crashing and will respond successfully.
LimericksController#index
controller actionThere are a couple pieces of information that we must collect about the controller action we mean to test:
Open the config/routes.rb
file, and locate the route that calls this index
action. You should find this route:
root to: 'limericks#index'
Note that this is the root route for the app. The URL helper for the root route is root_url
.
Open the controller class file app/controllers/limericks_controller.rb
, which contains the LimericksController
class, in VS Code. Inspect the code related to the index
method. You should see the following.
class LimericksController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :require_permission, except: [:index, :new, :create]
def index
@limericks = Limerick.all.reverse_order
render :index
end
...
Note that (as per the before_action
declarations) no user authentication is required to run the index
action. Also note that the index
action behaves in the usual way, retrieving a collection of limericks from the database and rendering a view template app/views/limericks/index.html.erb
.
LimericksController#index
Each automated test we write can divided into three steps:
assert
command.To test the LimericksController#index
action, we plan each of these steps as follows:
index
controller test, we will do the following checks:
Limerick
fixtures.The controller tests for the LimericksController
controller class should go in the LimericksControllerTest
controller test class (defined in test/controller/limericks_controller_test.rb
). Note that, in general, for a controller class defined in app/controllers/xxxxx_controller.rb
, the controller test class for that controller should be defined in test/controllers/xxxxx_controller_test.rb
.
Open the controller test file test/controller/limericks_controller_test.rb
in VS Code. It should contain only one test case, the "the truth"
test case we uncommented previously.
test "the truth" do
assert true
end
Edit the name of the test case to "should get index"
to communicate the action under test (index
) and the expected result (“should get”, success being implied by “should”).
test "should get index" do
assert true
end
Arrange. Store the number of Limerick
fixtures in a variable, so in the Assert step, we can check that the correct number of limerick cards are rendered on the index page.
test "should get index" do
limericks_size = limericks.size
assert true
end
Note that the call to limericks
retrieves all the Limerick
fixture objects from the database. For each fixture file, Rails provides a method of the same name for retrieving the fixtures.
Act. Use the get
command to simulate an HTTP GET request with the URL for the root route as follows.
test "should get index" do
limericks_size = limericks.size
get root_url
assert true
end
Assert. Replace the assert true
call with with a call to assert_response
that checks that the HTTP response produced by the app has a success code (a 2xx status code, like 200 OK
).
test "should get index" do
limericks_size = limericks.size
get root_url
assert_response :success
end
Add an additional call to assert_select
that checks that the correct number of cards were rendered on the page.
test "should get index" do
limericks_size = limericks.size
get root_url
assert_response :success
assert_select 'div.card', limericks_size
end
Note that the call to assert_select
counts the number of HTML div
elements with CSS class card
and checks that the count is equal to limericks_size
(the number of Limerick
fixtures).
Run the following command to run all test cases defined in the project.
rails test -v
The output of the command should look like the following.
Running 1 tests in a single process (parallelization threshold is 50)
Run options: -v --seed 29234
# Running:
LimericksControllerTest#test_should_get_index = 2.17 s = .
Finished in 2.178224s, 0.4591 runs/s, 0.9182 assertions/s.
1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
Note that the output mentions that 1 test ran (LimericksControllerTest#test_should_get_index
) and that test had 2 assertions, which makes sense because we called assert_response
and assert_select
. If either assertion had failed, an error message would have been displayed, and the failure count would have been greater than zero. If the app had crashed while processing the request, error messages would have been displayed, and the error count would have been greater than zero.
⏴ Back | Next ⏵ |