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#indexEach 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 ⏵ |