Test::Unit abstract test case
Having found a new way to structure my tests, the need for some common setup shared by multiple test cases became apparent.
I think the traditional way to do this was to create a subclass of TestCase to contain the common setup code and then subclass that for your individual test cases. This is fine, but in test/unit, a TestCase with no tests causes an error.
One solution would be to use a module to contain the common setup and include that in your test case.
module CommonSetup
def setup
@stack = Stack.new
end
end
class MyTest < Test::Unit::TestCase
include CommonSetup
def test_should_accept_an_item_when_sent_push
assert_nothing_raised { @stack.push(1) }
end
end
Although this is fine, I spent a short while creating an AbstractTestCase that doesn’t complain if no tests are specified.
require 'test/unit'
class Test::Unit::AbstractTestCase < Test::Unit::TestCase
def default_test
klass = self.class.to_s
ancestors = (self.class.ancestors - [self.class]).collect { |ancestor| ancestor.to_s }
super unless klass =~ /AbstractTestCase/ or ancestors.first =~ /AbstractTestCase/
end
end
Any test case (TestBase in this example) that inherits from AbstractTestCase can now contain setup and teardown methods but not have to worry about missing tests. In order to maintain expected behaviour, any test case subclassed from TestBase will still complain if tests are missing.
class TestBase < Test::Unit::AbstractTestCase
# 'No test were specified' error is not thrown
def setup
@bar = { :foo => 123 }
end
end
class RealTest < TestBase
# Utilises TestBase#setup
def test_example
assert_equal 123, @bar[:foo]
end
end
class ShouldErrorTest < TestBase
# 'No tests were specified' error
end
I then figured that you may want more than one level of abstract test case, i.e. be able to define at the TestCase class level whether or not a test case was abstract. This isn’t properly tested but it seems to work ok.
Note This isn’t doing exactly what I thought (the default test case is default_test, not test_default). This works because it just creates an empty test in your test case. This breaks behaviour in test cases that subclass your abstract test case as they too will already have at least one test defined.
require 'test/unit'
class Test::Unit::TestCase
class << self
def abstract
self.class_eval do
def test_default
end
end
end
end
end
By sending the abstract message to any TestCase class, no errors will be reported when no tests are specified. It does this by overriding the test_default method; which is the method that raises the error if no other tests are specified.
class AbstractTest < Test::Unit::TestCase abstract # 'No test were specified' error is not thrown end class NormalTest < Test::Unit::TestCase # 'No test were specified' error end