Module: Test::Rails
- Defined in:
- lib/test/rails.rb,
lib/test/rails/version.rb
Overview
Introduction
Test::Rails helps you build industrial-strength Rails code by:
-
testing views separate from controllers
-
enhancing the assertion vocabulary, and
-
auditing your tests for consistency.
Details
Test::Rails:
-
splits Functional test into Controller and View tests.
-
Splits view assertions away from controller assertions.
-
Helps decouple views from controllers.
-
Allows you to test AJAX actions in isolation.
-
Allows you to test a single partial.
-
Clearer failures when assert_tag fails.
-
-
An auditing script analyzes missing assertions in your controllers and views.
-
Library of assertions for testing views.
How to Convert to Test::Rails
You will need to make three small changes to test/test_helper.rb to set up Test::Rails:
First, add the following to ‘test/test_helper.rb’ before you require test_help
:
require 'test/rails'
Next, change the class from “Unit” to “Rails” right after you require test_help
.
Your ‘test/test_helper.rb’ will end up looking like this:
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test/rails'
require 'test_help'
class Test::Rails::TestCase
...
Finally, you need to add the extra rake tasks Test::Rails provides. Add the following line to your Rakefile after you require ‘tasks/rails’:
require 'test/rails/rake_tasks'
NOTE:
-
get/post/etc. no longer have a session or flash argument. Use the session and flash accessor instead.
-
assert_tag will (eventually) not work in controller tests.
Writing View Tests
View tests live in test/views. They are named after the controller that is being tested. For exampe, RouteViewTest will live in the file test/views/route_view_test.rb.
Example View Test Case
require 'test/test_helper'
# We are testing RouteController's views
class RouteViewTest < Test::Rails::ViewTestCase
fixtures :users, :routes, :points, :photos
# testing the view for the delete action of RouteController
def test_delete
# Instance variables necessary for this view
assigns[:loggedin_user] = users(:herbert)
assigns[:route] = routes(:work)
# render this view
render
# assert everything is as it should be
assert_links_to "/route/flickr_refresh/#{routes(:work).id}"
form_url = '/route/destroy'
assert_post_form form_url
assert_input form_url, :hidden, :id
assert_submit form_url, 'Delete!'
assert_links_to "/route/show/#{routes(:work).id}", 'No, I do not!'
end
# ...
end
All view tests are a subclass of Test::Rails::ViewTestCase. The name of the subclass must match the controller this view depends upon. ViewTestCase takes care of all the setup necessary for running the tests.
The test_delete
method is named after the delete method in RouteController. The ViewTestCase#render method looks at the name of the test and tries to figure out which view file to use, so naming tests after actions will save you headaches and typing.
Use assigns
to set up the variables the view will use when it renders.
The call to render is the equivalent to a functional tests’ get/post methods. It makes several assumptions, so be sure to read ViewTestCase#render carefully.
ViewTestCase has a vastly expanded assertion library to help you out with testing. See ViewTestCase for all the helpful assertions you can use in your view tests.
Writing Controller Tests
Controller tests are essentially functional tests without the view assertions.
They live in test/controllers, subclass ControllerTestCase, and are named after the controller they are testing. For example, RouteControllerTest will live in the file test/controllers/route_controller_test.rb.
Example Controller Test Case
require 'test/test_helper'
# We are testing RouteController's actions
class RouteControllerTest < Test::Rails::ControllerTestCase
fixtures :users, :routes, :points, :photos
# Testing the delete method
def test_delete
# A session accessor is provided instead of passing a hash to get.
session[:username] = users(:herbert).username
get :delete, :id => routes(:work).id
# assert we got a 200
assert_success
# assert that instance variables are correctly assigned
assert_assigned :action_title, "Deleting \"#{routes(:work).name}\""
assert_assigned :route, routes(:work)
end
# ...
end
Writing Abstract Test Cases
Abstract test cases are a great way to refactor your tests and ensure you do not violate the DRY principal and share code between different test classes. If you have common setup code for your test classes you can create your own subclass of ControllerTestCase or ViewTestCase.
Example Abstract Test Case
class RobotControllerTestCase < Test::Rails::ControllerTestCase
fixtures :markets, :people
def setup
super
# We're running tests in this class so we don't need to do any more
# setup
return if self.class == RobotControllerTestCase
# Set our current host
@host = 'www.test.robotcoop.com'
util_set_host @host
end
##
# Sets the hostname to +host+ for this request.
def util_set_host(hoston)
@request.host = host
end
end
How to Audit Your Tests
bin/rails_test_audit
ensures that your view tests’ assigns are compared against your controller tests’ assert_assigned, warning you when you’ve forgotten to test something.
Given:
class RouteControllerTest < Test::Rails::ControllerTestCase
def test_flickr_refresh
get :flickr_refresh, :id => routes(:work).id
assert_success
assert_assigned :tz_name, 'Pacific Time (US & Canada)'
end
end
And:
class RouteViewTest < Test::Rails::ViewTestCase
def test_flickr_refresh
assigns[:route] = routes(:work)
assigns[:tz_name] = 'Pacific Time (US & Canada)'
render
# ...
end
end
rails_test_audit
will see that you don’t have an assert_assigned
for route
and will output:
require 'test/test_helper'
class RouteControllerTest < Test::Rails::ControllerTestCase
def test_flickr_refresh
assert_assigned :route, routes(:work)
end
end
How ‘rake test’ Changed
test:views and test:controllers targets get added so you can run just the view or controller tests.
The “test” target runs tests in the following order: units, controllers, views, functionals, integration.
The test target no longer runs all tests, it stops on the first failure. This way a failure in a unit test doesn’t fill your screen with less important errors because the underlying failure also affected your controllers and views.
The stats target is updated to account for controller and view tests.
Defined Under Namespace
Modules: VERSION Classes: ControllerTestCase, FunctionalTestCase, HelperTestCase, IvarProxy, TestCase, ViewTestCase
Class Method Summary collapse
-
.rails_version ⇒ Object
The currently loaded rails version.
-
.v1_2 ⇒ Object
:nodoc:.
Class Method Details
.rails_version ⇒ Object
The currently loaded rails version. Better than Rails::VERSION::STRING since this one is comparable.
264 265 266 |
# File 'lib/test/rails.rb', line 264 def self.rails_version @rails_version end |
.v1_2 ⇒ Object
:nodoc:
268 269 270 |
# File 'lib/test/rails.rb', line 268 def self.v1_2 # :nodoc: @v1_2 end |