RSpec:DRY测试一组值的方法

时间:2011-04-03 02:44:26

标签: ruby-on-rails ruby-on-rails-3 refactoring rspec dry

我有一个vote模型,它有一个名为score的类方法。基本上,我在电子表格中创建了一个数学方程式,并试图在ruby中重现这一点。但是,我的第一次工作没有用,所以我真的需要开始增加更多的测试。

我想对此进行测试的方法是从电子表格中获取一堆输入和输出值并对其进行测试。所以基本上,测试可以解释为这样:

 inputs = [a,b,c] ... score.should == x
 inputs = [a,b,c,d] ... score.should == y
 inputs = [c,d] .... score.should == z

然而,我实际上发现在RSpec中写这个的最短路径就是为每个案例提供一个例子,大概是这样的(简化示例,但应该给你一个想法):

it "should have a score of X" do
  test_object = Votable.new(...)
  @user1.vote.create(:value=>##, :votable=>test_object)
  @user2.vote.create(:value=>##, :votable=>test_object)
  @user3.vote.create(:value=>##, :votable=>test_object)
  test_object.votes.score.should == X
end

所以,上面的工作,但每个示例案例的文本负载,并解决扭结并提供良好的测试覆盖率我想运行大约20个左右的测试用例。

所以,说真的,必须有一种更简单的方法来设置一次,然后测试一堆可能的输入/输出组合,对吧?任何人都可以建议在RSpec中进行这种测试吗?

谢谢!

2 个答案:

答案 0 :(得分:5)

是的,您可以执行以下元编程来运行一系列测试,所有测试都遵循相同的格式:

results = { x: ['a', 'b', 'c'], y: ['a','b','c','d'] }

results.each do |score, values|
  it "should have a score of #{score}" do
    test_object = Votable.new(...)
    values.each do |value|
      User.create(...).vote.create(value: value, votable: test_object)
    end
    test_object.votes.score.should == score
  end
end

答案 1 :(得分:0)

@Pan Thomakos:

你的回答激发了我的灵感(所以我接受了它!)但实际上,根据你的建议,我创造了一些不同的东西。我很高兴,我以为我会分享它,以防其他人受益。

以前我的模型有这个方法:

def self.score
  dd = where( :value => -2 ).count.to_f
  d = where( :value => -1 ).count.to_f
  u = where( :value => 1 ).count.to_f
  uu = where( :value => 2 ).count.to_f
  tot = dd + d + u + uu
  score = (((-5*dd)+(-2*d)+(2*u)+(5*uu))/(tot+4))*20
  score.round(2)
end

这有效,但它需要对数据库中的投票进行计数,查看每个可能值(-2,-1,+ 1,+ 2)的投票数,然后根据这些计数计算得分。

由于我需要测试的不是ActiveRecord查找和计算查询结果的能力,而是我将这些计数转换为分数的算法,我将其分为两种方法,如下所示:

def self.score
  dd = where( :value => -2 ).count
  d = where( :value => -1 ).count
  u = where( :value => 1 ).count
  uu = where( :value => 2 ).count

  self.compute_score(dd,d,u,uu)
end

def self.compute_score(dd, d, u, uu)
  tot = [dd,d,u,uu].sum.to_f
  score = [-5*dd, -2*d, 2*u, 5*uu].sum / [tot,4].sum*20.0
  score.round(2)
end

所以现在我可以测试compute_score方法,而无需创建一堆虚假用户和虚假投票来测试算法。我的测试现在看起来像:

describe "score computation" do
  def test_score(a,b,c,d,e)
    Vote.compute_score(a,b,c,d).should == e
  end

  it "should be correct" do
    test_score(1,0,0,0,-20.0)
    test_score(0,1,0,0,-8.0)
    test_score(0,0,1,0,8.0)
    test_score(0,0,0,1,20.0)

    test_score(0,0,10,100,91.23)
    test_score(0,6,60,600,92.78)
    test_score(0,20,200,2000,93.17)
  end
end

在我看来,这是非常清晰的,如果我向RSpec询问格式化的输出,那么它的读数就足够了。

希望这项技术对其他人有用!