ProblemYou want to ensure that your application's controllers behave as expected when responding to HTTP requests. SolutionYou have an existing database application. This application consists of a Books Controller containing list, show, and search actions. app/controllers/books_controller.rb: class BooksController < ApplicationController def list @book_pages, @books = paginate :books, :per_page => 10 end def show @book = Book.find(params[:id]) end def search @book = Book.find_by_isbn(params[:isbn]) if @book redirect_to :action => 'show', :id => @book.id else flash[:error] = 'No books found.' redirect_to :action => 'list' end end end You have the following test fixture for testing: test/fixtures/books.yml: learning_python_book: id: 2 isbn: 0596002815 title: Learning Python description: Essential update of a steady selling "Learning" series book Add the following test_search_book and test_search_invalid_book methods to books_controller_test.rb to test the functionality of the Book Controller's search action. test/functional/books_controller_test.rb: require File.dirname(__FILE__) + '/../test_helper' require 'books_controller' # Re-raise errors caught by the controller. class BooksController; def rescue_action(e) raise e end; end class BooksControllerTest < Test::Unit::TestCase fixtures :books def setup @controller = BooksController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end def test_search_book get :search, :isbn => '0596002815' assert_not_nil assigns(:book) assert_equal books(:learning_python_book).isbn, assigns(:book).isbn assert_valid assigns(:book) assert_redirected_to :action => 'show' end def test_search_invalid_book get :search, :isbn => 'x123x' # invalid ISBN assert_redirected_to :action => 'list' assert_equal 'No books found.', flash[:error] end end Run the test with: $ ruby test/functional/books_controller_test.rb Loaded suite test/functional/books_controller_test Started .. Finished in 0.132993 seconds. 2 tests, 9 assertions, 0 failures, 0 errors DiscussionTesting a controller requires reproducing the HTTP environment in which the controller runs. When using Rails, you can reproduce this environment by instantiating request and response objects (to simulate a request from a browser), in addition to the controller being tested. These objects are created in the setup method. To write a functional test, you need to simulate any of the five HTTP request types that your controller will process. Rails provides methods for all of these:
Most applications use only get and post. All these methods take four arguments:
By using these request methods and their optional arguments, you can reproduce any request that your controllers could possibly encounter. Once you've simulated a browser request, you'll want to inspect the impact it had on your controller. You can view the state of the variables that were set during the processing of a request by inspecting any of these four hashes:
The contents of these hashes can be tested with assert_equal and other assertions. The goal of the BooksControllerTest class is to test that the controller's search action does the right thing when supplied with valid and invalid input. The first test method (t est_search_book) generates a get request to the search action, passing in an ISBN parameter. The next two assertions verify that a Book object was saved in an instance variable called @book and that the object passes any Active Record validations that might exist. The final assertion tests that the request was redirected to the controller's show action. The second test method, test_search_invalid_book, performs another get request but passes in an ISBN that doesn't exist in the database. The first two assertions test that the @book variable contains nil and that a redirect to the list action was issued. If the proceeding assertions passed, there should be a message in the flash hash; you can test for this assertion with assert_equal. Once again, Rails really helps by creating much of the functional test code for you. For example, when you create scaffolding for a model, Rails automatically creates a functional test suite with 8 tests and almost 30 assertions. By running these tests every time you make a change to your controllers, you can greatly reduce the number of hard-to-find bugs. See Also
|