1

当我对我不太信任的代码进行单元测试时,我通常会使用这种模式:

  1. 想想我对函数输出的许多(可能是几十个)期望(我认为这些是关于代码如何工作的“理论”)。
  2. 旋转数以千计的对象。
  3. 通过我编写的数十个断言运行每个对象,这些断言反映了我对代码工作方式的期望。

在 Ruby 的 Test::Unit (我是新手)中,我一直在做这样的事情:

class TestFooBarrer < Test::Unit::TestCase
  def setup
    @lots_of_objects_to_be_tested = FooBarrer.bar_lots_of_foos
  end

  def assert_foo_has_been_barred(foo)
    assert_kind_of Bar, foo
  end

  def assert_foo_has_baz_method(foo)
    assert_respond_to foo, :baz
  end

  #Many more assertions along those lines go here.

  def test_all_theories
    @lots_of_objects_to_be_tested.each do |foo|
      assert_foo_has_been_barred(foo)
      assert_foo_has_baz_method(foo)
      # etc.
      #
    end
  end
end

当我正在测试的理论数量有几十个时,这显然会变得有点笨拙,并且涉及到在我看来很多不必要的重复。我宁愿做这样的事情:

class FooTheories
  def self.assert_all_theories(foo)
    # ???
  end

  def assert_foo_has_been_barred(foo)
    assert_kind_of Bar, foo
  end

  def assert_foo_has_baz_method(foo)
    assert_respond_to foo, :baz
  end

  #Many more assertions along those lines go here.
end


class TestFooBarrer < Test::Unit::TestCase
  def setup
    @lots_of_objects_to_be_tested = FooBarrer.bar_lots_of_foos
  end

  def test_all_theories
    @lots_of_objects_to_be_tested.each do |foo|
      FooTheories.assert_all_theories(foo)
    end
  end
end

基本上,我正在寻找一种方法来在一个地方编写一堆断言,然后在大量对象上一遍又一遍地调用它们。

Ruby 中是否有类似的支持?我与 Test::Unit 无关。任何测试框架都可以。

4

1 回答 1

1

我要做的是即时生成测试。在 test_helper 中添加一个方法:

def test(obj, &block)
  define_method("test_#{ obj.to_s }", &block)
end

然后你可以像下面这样制作你的测试套件

class TestObjects < Test::Unit::TestCase

  @objects_to_test = [...]

  @objects_to_test.each do |obj|
    test obj do

      assert obj.is_a?(Foo), 'not a foo'

      # all assertions here

    end
  end

end

然后如果它失败了,你会知道哪个对象失败了,因为测试的名称是对象的字符串表示。前消息:

1) Failure:
test_#<Bar:0x000001009ee930>(TestObjects):
not a foo
于 2013-02-15T19:57:54.180 回答