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.

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.

Base App Code

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 1 Changeset

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 2 Changeset

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”.

Step 3 Changeset

Conclusion

Following the above steps, we have now added an automated controller test for the about page of the Billy Books bookstore app.

Demo App Code