如何在Ruby中批量单元测试对象集合?

时间:2013-02-15 18:16:52

标签: ruby unit-testing

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

  1. 想想我对函数输出的许多(也许几十个)期望(我认为这些是关于代码如何工作的“理论”)。
  2. 旋转数千个物体。
  3. 通过我编写的几十个断言来运行每个对象,反映出我对代码如何工作的期望。
  4. 在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。任何测试框架都可以。

1 个答案:

答案 0 :(得分: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