In Ruby's Test::Unit::TestCase, how do I override the initialize method?
As mentioned in Hal Fulton's book "The Ruby Way".He overrides the self.suite method of Test::Unit which allows the test cases in a class to run as a suite.
def self.suite mysuite = super def mysuite.run(*args) MyTest.startup() super MyTest.shutdown() end mysuiteend
Here is an example:
class MyTest < Test::Unit::TestCase class << self def startup puts 'runs only once at start' end def shutdown puts 'runs only once at end' end def suite mysuite = super def mysuite.run(*args) MyTest.startup() super MyTest.shutdown() end mysuite end end def setup puts 'runs before each test' end def teardown puts 'runs after each test' end def test_stuff assert(true) endend
FINALLY, test-unit has this implemented! Woot! If you are using v 2.5.2 or later, you can just use this:
Test::Unit.at_start do # initialization stuff hereend
This will run once when you start your tests off. There are also callbacks which run at the beginning of each test case (startup), in addition to the ones that run before every test (setup).
http://test-unit.rubyforge.org/test-unit/en/Test/Unit.html#at_start-class_method
That's how it's supposed to work!
Each test should be completely isolated from the rest, so the setup
and tear_down
methods are executed once for every test-case. There are cases, however, when you might want more control over the execution flow. Then you can group the test-cases in suites.
In your case you could write something like the following:
require 'test/unit'require 'test/unit/ui/console/testrunner'class TestDecorator < Test::Unit::TestSuite def initialize(test_case_class) super self << test_case_class.suite end def run(result, &progress_block) setup_suite begin super(result, &progress_block) ensure tear_down_suite end endendclass MyTestCase < Test::Unit::TestCase def test_1 puts "test_1" assert_equal(1, 1) end def test_2 puts "test_2" assert_equal(2, 2) endendclass MySuite < TestDecorator def setup_suite puts "setup_suite" end def tear_down_suite puts "tear_down_suite" endendTest::Unit::UI::Console::TestRunner.run(MySuite.new(MyTestCase))
The TestDecorator
defines a special suite which provides a setup
and tear_down
method which run only once before and after the running of the set of test-cases it contains.
The drawback of this is that you need to tell Test::Unit how to run the tests in the unit. In the event your unit contains many test-cases and you need a decorator for only one of them you'll need something like this:
require 'test/unit'require 'test/unit/ui/console/testrunner'class TestDecorator < Test::Unit::TestSuite def initialize(test_case_class) super self << test_case_class.suite end def run(result, &progress_block) setup_suite begin super(result, &progress_block) ensure tear_down_suite end endendclass MyTestCase < Test::Unit::TestCase def test_1 puts "test_1" assert_equal(1, 1) end def test_2 puts "test_2" assert_equal(2, 2) endendclass MySuite < TestDecorator def setup_suite puts "setup_suite" end def tear_down_suite puts "tear_down_suite" endendclass AnotherTestCase < Test::Unit::TestCase def test_a puts "test_a" assert_equal("a", "a") endendclass Tests def self.suite suite = Test::Unit::TestSuite.new suite << MySuite.new(MyTestCase) suite << AnotherTestCase.suite suite endendTest::Unit::UI::Console::TestRunner.run(Tests.suite)
The Test::Unit documentation documentation provides a good explanation on how suites work.