Recipe 7.18. Unit Testing Model Validations


Problem

You need to ensure that your application's data is always consistent; that is, that your data never violates certain rules imposed by your application's requirements. Furthermore, you want to be sure that your validations work as expected by testing them with unit tests.

Solution

Active Record validations are a great way to ensure that your data remains consistent at all times. Assume you have a books table that stores the title and ISBN for each book as created by the following migration:

db/migrate/001_create_books.rb:

class CreateBooks < ActiveRecord::Migration   def self.up     create_table :books do |t|       t.column :title, :string       t.column :isbn, :string     end   end   def self.down     drop_table :books   end end

Instantiate the schema of your test database:

$ rake db:test:clone_structure             

Next, create two book records in your fixtures file: one consisting of a title and valid ISBN and another with an invalid ISBN:

test/fixtures/books.yml:

java_cb:   id: 1   title: 'Java Cookbook'   isbn: '0596007019' bad_cb:   id: 2   title: 'Bad Cookbook'   isbn: '059600701s'

Create an Active Record validation to check the format of ISBNs in the Book model class definition.

class Book < ActiveRecord::Base   validates_format_of :isbn, :with => /^\d{9}[\dxX]$/ end

Now define a test method named test_isbn_validation in the BookTest test case:

test/unit/book_test_validation.rb:

require File.dirname(__FILE__) + '/../test_helper' class BookTest < Test::Unit::TestCase   fixtures :books   def test_isbn_validation     assert_kind_of Book, books(:java_cb)     java_cb = Book.new     java_cb.title = books(:java_cb).title     java_cb.isbn = books(:java_cb).isbn     assert java_cb.save     java_cb.isbn = books(:bad_cb).isbn     assert !java_cb.save     assert java_cb.errors.invalid?('isbn')   end end

Finally, run the test case with the command:

$ ruby ./test/unit/book_test_validation.rb             

Discussion

The call to fixtures :books at the beginning of the BookTest class includes the solution's labeled book fixtures. The objective of test_isbn_validation is to determine whether saving a Book object triggers the validation code, which makes sure the Book object's ISBN has the correct format. First, a new Book object is created and stored in the java_book instance variable. That object is assigned a title and a valid ISBN from the java_cb test fixture. java_cb.save attempts to save the object, and the assertion fails if the cookbook was not saved correctly.

The second part of this test method makes sure that validation is preventing a book with an invalid ISBN from being saved. It's not enough just to test the positive case (books with correct data are saved correctly); we also have to make sure that the assertion is keeping bad data out of the database. The bad_cb fixture contains an invalid ISBN (note the "s" at the end). This bad ISBN is assigned to the java_book object, and a save is attempted. Because this save should fail, the assert expression is negated. This way, when the validation fails, the assertion passes. Finally, we test that saving a book object with an invalid ISBN adds the isbn key and a failure message to the @errors array of the ActiveRecord::Errors object. The invalid? method returns TRue if the specified attribute has errors associated with it.

The output of running the test confirms that all four assertions test passed:

$ ruby ./test/unit/book_test_validation.rb Loaded suite book_test_validation Started . Finished in 0.057269 seconds. 1 tests, 4 assertions, 0 failures, 0 errors

See Also

  • Section 7.7"




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