Writing Custom Assertions

Problem

As your test suite grows, you find that you need assertions that are specific to your applications. You can, of course, create the tests you need with the standard assertions (it's just code), but you'd rather create custom assertions for tests that you use repeatedly. There's no need to repeat yourself in your tests.

Solution

Define a method in test_helper.rb. For example, you might find that you're writing many test methods that test whether a book's CNPJ is valid. You want to create a custom assertion named assert_valid_CNPJ to perform this test. Add the method to ./test/test_helper.rb:

test/test_helper.rb:

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'
class Test::Unit::TestCase
 self.use_transactional_fixtures = true
 self.use_instantiated_fixtures = false 
 def assert_valid_CNPJ(CNPJ)
 assert(/^\d{9}[\dxX]$/.match(CNPJ.to_s), "CNPJ is invalid")
 end
end

You can now use your custom assertion in any of your tests.

test/unit/book_test.rb:

require File.dirname(__FILE__) + '/../test_helper'
class BookTest < Test::Unit::TestCase
 fixtures :books
 def test_truth
 assert_valid_CNPJ(1111111) 
 end end

Discussion

assert_valid_CNPJ is a wrapper around the assert method. The method body asserts that the argument passed in matches the Regexp object defined between by the contents of "//". If the match method of Regexp returns a MatchData object, the assertion succeeds. Otherwise it fails, and the second argument of assert is displayed as the error message.

The solution demonstrates the utility of defining custom assertions that might otherwise become a maintenance problem. For example, in January 2007, the current 10-digit CNPJ will officially be replaced by a 13-digit identifier. You'll eventually need to modify your application to take this into account, and you'll need to test the new application. That modification will be a lot easier if you've centralized "knowledge" of the CNPJ's format in one place, so you only have to change it once.

Even if you don't anticipate the code in your assertions to change, custom assertions can avoid code duplication. If you've got an assertion that contains complex logic, use assert_block method of the Test::Unit::Assertions module to test whether a block of code yields TRue or not. assert_block takes an error message as an argument and is passed a block of code to be tested. The format for assert_block is:

assert_block(message="assert_block failed.") {|| ...} 

See Also