In Ruby's Test::Unit::TestCase, how do I override the initialize method? In Ruby's Test::Unit::TestCase, how do I override the initialize method? ruby ruby

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.