Recipe 7.13. Testing Controllers with Functional Tests


Problem

You want to ensure that your application's controllers behave as expected when responding to HTTP requests.

Solution

You 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

Discussion

Testing 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:

  • get

  • post

  • put

  • head

  • delete

Most applications use only get and post. All these methods take four arguments:

  • The action of a controller

  • An optional hash of request parameters

  • An optional session hash

  • An optional flash hash

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:


assigns

Contains instance variables assigned within actions


cookies

Contains any cookies that exist


flash

Contains objects of flash component of the session hash


session

Contains objects stored as session variables

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

  • Section 7.12"




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net