Search code examples
rubyunit-testinginheritancetestunit

How do I inherit abstract unit tests in Ruby?


I have two unit tests that should share a lot of common tests with slightly different setup methods. If I write something like

class Abstract < Test::Unit::TestCase
  def setup
    @field = create
  end

  def test_1
    ...
  end
end

class Concrete1 < Abstract
  def create
    SomeClass1.new
  end
end

class Concrete2 < Abstract
  def create
    SomeClass2.new
  end
end

then Concrete1 does not seem to inherit the tests from Abstract. Or at least I cannot get them to run in eclipse. If I choose "Run all TestCases" for the file that contains Concrete1 then Abstract is run even though I do not want it to be. If I specify Concrete1 then it does not run any tests at all! If I specify test_1 in Concrete1 then it complains it cannot find it ("uncaught throw :invalid_test (ArgumentError)").

I'm new to Ruby. What am I missing here?


Solution

  • The issue is that, as far as I can tell, Test::Unit keeps track of which classes inherit from Test::Unit::TestCase, and as a result, will only run tests from classes that directly inherit from it.

    The way to work around this is to create a module with the tests you want, and then include that module in the classes that derive from Test::Unit::TestCase.

    require 'test/unit'
    
    module TestsToInclude
      def test_name
        assert(self.class.name.start_with?("Concrete"))
      end
    end
    
    class Concrete1 < Test::Unit::TestCase
      include TestsToInclude
    
      def test_something_bad
        assert(false)
      end
    end
    
    class Concrete2 < Test::Unit::TestCase
      include TestsToInclude
    
      def test_something_good
        assert(true)
      end
    end
    

    Output:

    Loaded suite a
    Started
    .F..
    Finished in 0.027873 seconds.
    
      1) Failure:
    test_something_bad(Concrete1) [a.rb:13]:
    <false> is not true.
    
    4 tests, 4 assertions, 1 failures, 0 errors
    
    shell returned 1