如何在Ruby中inheritance抽象unit testing?

我有两个unit testing,应该使用略有不同的设置方法共享许多常见测试。 如果我写的东西像

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 

然后Concrete1似乎没有从Abstractinheritance测试。 或者至少我不能让它们在日食中运行。 如果我为包含Concrete1的文件选择“Run all TestCases”,那么即使我不想要它也会运行Abstract。 如果我指定Concrete1那么它根本不运行任何测试! 如果我在Concrete1中指定test_1,那么它会抱怨它无法找到它(“uncaught throw:invalid_test(ArgumentError)”)。

我是Ruby的新手。 我在这里想念的是什么?

问题是,据我所知, Test::Unit跟踪哪些类inheritance自Test::Unit::TestCase ,因此, 只会直接从它inheritance的类中运行测试。

解决此问题的方法是使用所需的测试创建一个模块,然后将该模块包含在派生自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 

输出:

装载套房
入门
 。F..
完成时间为0.027873秒。

   1)失败:
 test_something_bad(Concrete1)[a.rb:13]:
 不是真的。

 4次测试,4次断言,1次失败,0次错误

 shell返回1

问题是Test::Unit::TestCase默认情况下不会运行超类中定义的测试。 特别要注意,除非Test::Unit::TestCase#valid?否则TestSuiteCreator不会运行测试Test::Unit::TestCase#valid? 返回true( https://github.com/test-unit/test-unit/blob/2.5.5/lib/test/unit/testsuitecreator.rb#L40 ):

 def append_test(suite, test_name) test = @test_case.new(test_name) yield(test) if block_given? suite << test if test.valid? end 

是什么决定了测试用例是否有效? 如果此类显式定义了该方法,或者该方法是在Module定义的,则测试用例默认有效( https://github.com/test-unit/test-unit/blob/2.5.5/lib/ test / unit / testcase.rb#L405-L418 ):

 def valid? # :nodoc: return false unless respond_to?(@method_name) test_method = method(@method_name) if @internal_data.have_test_data? return false unless test_method.arity == 1 else return false unless test_method.arity <= 0 end owner = Util::MethodOwnerFinder.find(self, @method_name) if owner.class != Module and self.class != owner return false end true end 

所以基本上,如果你inheritance了另一个unit testing类,并且想要运行超类的unit testing,你可以:

  • 重新定义子类中的那些测试方法,并让它们调用超类的测试方法
  • 将所有方法移动到模块(如本主题中的其他答案中所述)
  • 重新定义valid? 子类中的方法返回true:

def valid? return true end