RSpec:测试一组值的 DRY 方法

发布于 2024-10-30 16:31:59 字数 903 浏览 0 评论 0原文

我有一个 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 中进行此类测试的 DRY 方法?

谢谢!

I have a vote model, which has a class method called score. Basically, I created a mathematical equation in a spreadsheet, and am attempting to reproduce this in ruby. However, my first go isn't working, so I really need to start adding a ton more tests.

The way I'd like to go about testing this is to take a stack of input and output values from my spreadsheet and test them each. So basically, the tests could be construed to look like this:

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

However, the shortest way I've actually found to write this in RSpec is giving an example for each case, approximately like this (simplified example, but should give you the idea):

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

So, the above works, but its a load of text for each example case, and to iron out the kinks and provide good test coverage I'd like to run about 20 or so test cases.

So, seriously, there must be a simpler way to set this up one time and then test a bunch of possible input/output combinations, right? Can anyone suggest a DRY way to do this kind of test in RSpec?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

翻了热茶 2024-11-06 16:31:59

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

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

Yeah, you could do the following meta-programming to run a series of test that all follow the same format:

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
千纸鹤带着心事 2024-11-06 16:31:59

@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< /code> 方法,无需创建一堆假用户和假投票来测试算法。我的测试现在看起来像:

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 询问格式化输出,它对于测试的内容来说读起来足够好。

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

@Pan Thomakos:

Your answer inspired me (so I accepted it!) but I actually created something a little different inspired by your suggestion above. I'm so happy with it I thought I'd share it in case it benefits anyone else.

Previously my model had this method:

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

This worked, but it requires counting votes from the database, seeing the count of votes with each possible value (-2, -1, +1, +2) and then computing the score from these counts.

Since what I needed to test was not ActiveRecord's ability to find and count query results, but my algorithm for turning those counts into a score, I split this into two methods, like so:

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

So now I can just test the compute_score method without needing to create a bunch of fake users and fake votes to test the algorithm. My test now looks like:

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

In my opinion this is super legible, and if I ask RSpec for the formatted output it reads well enough for what it's testing.

Hopefully this technique will be useful for others!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文