如何在Ruby中继承抽象单元测试?

时间:2010-04-01 22:19:07

标签: ruby unit-testing inheritance testunit

我有两个单元测试,应该使用略有不同的设置方法共享许多常见测试。如果我写的话

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

我是Ruby的新手。我在这里缺少什么?

2 个答案:

答案 0 :(得分:7)

问题在于,就我所知,Test::Unit会跟踪哪些类继承自Test::Unit::TestCase,因此运行测试直接继承的类。

解决此问题的方法是创建一个包含所需测试的模块,然后在<{1}}派生的类中包含该模块。

Test::Unit::TestCase

输出:

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

答案 1 :(得分:1)

问题是Test::Unit::TestCase默认情况下不显式运行超类中定义的测试。请特别注意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

是什么决定了测试用例是否有效?如果此类明确定义该方法,或者该方法是在Modulehttps://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

所以基本上,如果你继承了另一个单元测试类,并且想要运行超类的单元测试,你可以:

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

def valid? return true end