| Module | Test::Rails |
| In: |
lib/test/rails.rb
|
Test::Rails helps you build industrial-strength Rails code by:
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:
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.
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.
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.
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
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.
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
bin/rails_test_audit ensures that your view tests’ +assign+s 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
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.