当我决定不久前学习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)?如果没有那么框架可以做到什么?
答案 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?
,因为问号已经暗示了问题然而,最佳解决方案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