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

发布于 2024-08-27 06:45:33 字数 591 浏览 9 评论 0原文

我有两个单元测试,它们应该共享许多常见的测试,但设置方法略有不同。如果我写类似的东西

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 的文件选择“运行所有测试用例”,则即使我不希望它运行,也会运行 Abstract。如果我指定 Concrete1 那么它根本不运行任何测试!如果我在 Concrete1 中指定 test_1 ,那么它会抱怨找不到它(“uncaught throw :invalid_test (ArgumentError)”)。

我是红宝石新手。我在这里缺少什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

百思不得你姐 2024-09-03 06:45:33

问题是,据我所知, Test::Unit 跟踪哪些类继承自 Test::Unit::TestCase,因此,将直接继承自它的类运行测试。

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

输出:

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

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
甜警司 2024-09-03 06:45:33

问题是 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

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

所以基本上,如果您对另一个单元测试类进行子类化,并且想要运行超类的单元测试,您可以:

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

定义有效吗?
返回真
结束

The problem is that Test::Unit::TestCase explicitly doesn't run tests defined in superclasses by default. In particular, note that TestSuiteCreator does not run tests unless Test::Unit::TestCase#valid? returns 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

And what determines if a test case is valid? A test case is valid by default if the this class explicitly defined that method, or if the method was defined in a 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

So basically, if you subclass another unit test class, and you want to run the superclass's unit tests, you can either:

  • Redefine those test methods in your subclass and have them call your superclass's test method
  • Move all your methods to a module (as explained in the other answer in this thread)
  • Redefine the valid? method in your subclass to return true:

def valid?
return true
end

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文