相当于Ruby 1.9.2 Test :: Unit中的nUnit测试用例

时间:2011-04-06 12:48:42

标签: ruby unit-testing testunit

当我决定不久前学习Ruby时,我也决定开始使用单元测试和TDD方法。我开始使用Test :: Unit并编写了几个非常小的类来感受一般的单元测试,特别是Ruby和Test :: Unit。

到目前为止,一切都很简单,但后来我想做类似于nUnit的TestCase,因为我有20次测试,其中唯一改变的是输入和输出。

代码如下所示:

def test_2_inserted_return_true
    actual = @prime_generator.is_prime?(2)
    assert_equal(true, actual)
  end

  def test_3_inserted_return_true
      actual = @prime_generator.is_prime?(3)
      assert_equal(true, actual)
    end

  def test_5_inserted_return_true
    actual = @prime_generator.is_prime?(5)
    assert_equal(true, actual)
  end

从干旱的角度来看,这是非常可怕的。我想要的是类似于nUnit的TestCase。

这样的事情:

[TestCase(2.5d, 2d, Result=1.25d)]
[TestCase(-2.5d, 1d, Result = -2.5d)]
public double ValidateDivision(double numerator, double denominator)
{
    var myClass = new MyClass();
    return myClass.Divide(numerator,denominator);
}

我尝试使用Google搜索,但找不到有关Test :: Unit的任何信息。我在RSpec和Selenium上找到了一些,但这对我没有帮助。我也尝试在这里搜索,但也找不到任何东西。

我考虑过让测试方法采用参数但是再次定义方法......对此并不满意。此外,如果我没记错的话甚至不可能(我现在无法测试,或者我会测试)。

所以,我的问题是:是否可以使用Ruby中的Test :: Unit进行数据驱动测试(1.9.2)?如果没有那么框架可以做到什么?

3 个答案:

答案 0 :(得分:4)

让我们不要忘记好的循环:

def test_that_the_first_few_primes_are_detected_as_prime
  [2, 3, 5, 7, 11, 13, 17].each do |p|
    assert @primality_tester.prime?(p)
  end
end

有些人会使用元编程来定义单独的测试方法,但在这种情况下我觉得它有点过分了:

[2, 3, 5, 7, 11, 13, 17].each do |p|
  define_method :"test_that_#{p}_is_detected_as_prime" do
    assert @primality_tester.prime?(p)
  end
end

一般来说,我认为测试不应该是DRY。它们应该是DAMP(描述性和有意义的短语)。毕竟,测试是您的规范和文档,并且可能不熟悉Ruby甚至一般编程的人阅读。所以,我甚至不确定你的原始例子是不好的,特别是如果你像我上面那样清理它:

def test_that_2_is_detected_as_prime
  assert @primality_tester.prime?(2)
end

def test_that_3_is_detected_as_prime
  assert @primality_tester.prime?(3)
end

def test_that_5_is_detected_as_prime
  assert @primality_tester.prime?(5)
end

这就是我的所作所为:

  • 重命名测试:现在,测试名称形成一个完整的句子,它不会简单地重述测试的内容。
  • 使用assert代替assert_equal:无论如何,检查true的相等性几乎都不是一个好主意,并且assert 已经检查结果是真的,所以为什么要打扰?
  • @prime_generator重命名为@primality_tester,因为它不会生成素数,它只会检查数字是否为素数。
  • is_prime?重命名为prime?,因为问号已经暗示了问题
  • 最后,但肯定不是最不重要的:修复格式化,因为格式化不仅与标准的Ruby编码约定不一致,而且在本身内甚至不一致

然而,最佳解决方案IMO将是这样的:

def test_that_the_first_few_primes_are_detected_as_prime
  assert @primality_tester.prime?(2)
  assert @primality_tester.prime?(3)
  assert @primality_tester.prime?(5)
end

那里有重复,但重复是保持测试可读和可发音的必要条件。 DRY是生产代码的一个很好的原则,它不断发展和扩展,但是对于测试,DRY总是需要与DAMP进行平衡。 (也许编写一个自定义断言是有意义的,但我对此表示怀疑。至少我不能为一个人提出一个好名字,这总是一个提示。)

完全不同的方法是基于属性的检查,类似于Haskell的QuickCheck或.NET的Pex。有一个名为RushCheck的QuickCheck的Ruby端口,但它自2006年以来一直没有维护,维护只在几周前发现,还有很多工作要做,以便在最近的版本中加快速度。红宝石。

答案 1 :(得分:2)

你应该检查rspec进行单元测试:

require 'prime'

describe "Numbers List" do
  [2, 3, 5, 7, 11, 13, 17].each do |i|
    it "#{i} is prime" do
      i.prime?
    end
  end
end

运行产量:

scratch-1.9.2> rspec -cfn primes.rb 

Numbers List
  2 is prime
  3 is prime
  5 is prime
  7 is prime
  11 is prime
  13 is prime
  17 is prime

Finished in 0.00146 seconds
7 examples, 0 failures

答案 2 :(得分:0)

我是通过元编程实现的,使用了我在Jay Fields博客上找到的一些样本。工作得很好,但是对def_each的调用必须作为我的测试用例文件的第一行完成。希望这个例子可以帮助某些人,本来希望看到这个答案,但是学习define_method非常酷:)

def self.def_each(method_names, &block)
 method_names.each do |method_name|
  method_name_fixed="test_"+method_name     
  define_method method_name_fixed do
    instance_exec method_name, &block
   end
 end
end

@@servers = ["pixeltmp01.fetchback.com","pixeltmp02.fetchback.com","pixeltmp03.fetchback.com"]

# generate test methods using fixtures and any other testcase-specific data
def_each @@servers do |method_name|
 @fb.withPixelServer(method_name)
 self.LandingPixelM
end