Controller Tests Creating an Automated Test for a Webpage
In this demonstration, I will show how to create a controller test for an existing webpage. A controller test is an automated test that can be run to help ensure that the code for a webpage works correctly (e.g., is free of syntax errors).
General Steps
In general, the steps for creating a controller test for a webpage are as follows.
-
Step 1 Add an Empty Controller Test. This step declares a test method in which the code that performs the test will go.
-
Step 2 Simulate an HTTP Request. This step adds code to the controller test that simulates an HTTP request being sent to the web app. This code will cause the web app to execute as though it were actually handling an HTTP request sent from a web browser.
-
Step 3 Check for Expected Behavior. This step adds code to the controller test that checks whether the web app exhibited the correct behavior in processing the simulated HTTP request. This code typically involves one or more assertion statements. An assertion statement evaluates an object or expression to check if an expected result was produced. If a different result than the one expected is produced, then the test fails, revealing a defect.
Creating a Controller Test for the Billy Books About Webpage
To demonstrate the steps for creating a controller test, we will be creating one for the about page of the Billy Books bookstore base app.
Step 1 Add an Empty Controller Test
To begin our controller test for the about webpage, we declare an empty test in which the test logic will go. Each controller generated using the rails
command is given a controller-test class to hold tests related to the controller. Since the about webpage is managed by the PagesController
, we add our test to the PagesControllerTest
class (found in test/controllers/pages_controller_test.rb
), like this:
require 'test_helper'
class PagesControllerTest < ActionDispatch::IntegrationTest
test 'should get about' do
end
end
The above call to the test
method generates a test method, which is added to the parent class, PagesControllerTest
. The test
method takes two arguments. The first is a string that names the test ('should get about'
). Based on the string, the generated method will be named test_should_get_about_webpage
(i.e., prepending the test name with test_
and converting the spaces in the test name to underscores). The second argument is a block containing the logic for the test (i.e., beginning with do
and ending with end
). This block will become the body of the generated method.
Test It!
To confirm that we made this change correctly, we run the test we created, like this:
rails test
Technically, this command runs all the tests written for the web app, but so far, we have added only the one above.
The command should produce output similar to this:
Running via Spring preloader in process 32723
Run options: --seed 65160
# Running:
.
Finished in 0.206787s, 4.8359 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
Note that output says, “1 runs”, which comes from our one test written above. However, because our test contains no logic, we see zeros for all the other stats (i.e., “0 assertions, 0 failures, 0 errors, 0 skips”).
Step 2 Simulate an HTTP Request
To simulate a request for the about webpage, we first find the name of the URL helper method for the webpage, and then, we use the helper to simulate the request.
Substep Find the URL helper prefix. To find the URL helper prefix for the Billy Books about page, we will look in a listing of the web app’s routes for the route information regarding the about page. To get a listing of the routes, we run the following command in the terminal:
rails routes -E
This command outputs a long listing of route information. The route for the about page should have an HTTP verb of GET and a resource path (labeled “URI” in the listing) of /about
. We scan the list of routes for one matching these traits, and we find the following entry:
--[ Route 2 ]-------------------------------------------------------------------------------------------------------------------
Prefix | about
Verb | GET
URI | /about(.:format)
Controller#Action | pages#about
We see from this entry that the prefix for the about page is about
; thus, we know that the URL helper method for the about page is called about_url
.
Substep Simulate an HTTP GET request for the URL. To test the logic that handles requests for the about webpage, we add a line of code to our test that simulates an HTTP request for the about webpage, like this:
require 'test_helper'
class PagesControllerTest < ActionDispatch::IntegrationTest
test 'should get about' do
get about_url
end
end
The call to the get
method simulates an HTTP GET request. The get
method takes one argument, the URL being requested. For this argument, we call the about_url
helper method to retrieve the URL for the about page.
Test It!
To confirm that we made this change correctly, we run our updated test, like this:
rails test
The command should produce output similar to this:
Running via Spring preloader in process 32927
Run options: --seed 41762
# Running:
.
Finished in 3.347855s, 0.2987 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
The stats regarding runs, assertions, etc. remain unchanged since the previous step; however, we may notice that the time it took for the test to execute increased, because it added processing of the simulated request this time.
Step 3 Check for Expected Behavior
To help verify that the logic for handling the simulated request for the about webpage behaved correctly, we add to our test a call to the assert_response
assertion method that checks whether the HTTP response produced by the web app has a status code indicating success (e.g., 200 OK
), like this:
require 'test_helper'
class PagesControllerTest < ActionDispatch::IntegrationTest
test 'should get about' do
get about_url
assert_response :success
end
end
The assert_response
call takes one argument, a type of response status, and checks whether the app’s response to the simulated request has a status of that type. In the above call, the :success
symbol specifies that the assertion is checking for a successful response status. Being an assertion, the method will log a test failure if the response has an unsuccessful status. Such a failure would, for example, result in an error message appearing in the output of the rails test
command.
Note that this assertion will not detect all the possible errors we can imagine. For example, if the app responded with some other webpage than the about webpage, this test would not catch it. Rails offers a variety of assertions that can be used to check other aspects of the app’s behavior. However, that said, a test that merely checks for a successful response status still provides considerable benefits, including detection of any syntax errors and of a wide range internal failures that would either crash the app or result in a response with an unsuccessful status.
Test It!
To confirm that we made this change correctly, we run our updated test, like this:
rails test
The command should produce output similar to this:
Running via Spring preloader in process 33048
Run options: --seed 9547
# Running:
.
Finished in 0.388068s, 2.5769 runs/s, 2.5769 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
Since we added the assert_response
assertion to our test this time, we now see that the assertions stat has changed to “1 assertions”. Since the assertion passed, we see that, as before, there remain “0 failures”.
Conclusion
Following the above steps, we have now added an automated controller test for the about page of the Billy Books bookstore app.