当前位置:  开发笔记 > 后端 > 正文

随机生成测试数据是不好的做法?

如何解决《随机生成测试数据是不好的做法?》经验,为你挑选了3个好方法。

自从我开始使用rspec以来,我遇到了固定装置概念的问题.我主要担心的是:

    我使用测试来揭示令人惊讶的行为.对于我正在测试的示例,我并不总是能够枚举每个可能的边缘情况.使用硬编码灯具似乎有限,因为它只用我想象的非常具体的情况来测试我的代码.(不可否认,我的想象力也限制了我测试的情况.)

    我使用测试作为代码的文档形式.如果我有硬编码的夹具值,很难揭示特定测试试图演示的内容.例如:

    describe Item do
      describe '#most_expensive' do
        it 'should return the most expensive item' do
          Item.most_expensive.price.should == 100
          # OR
          #Item.most_expensive.price.should == Item.find(:expensive).price
          # OR
          #Item.most_expensive.id.should == Item.find(:expensive).id
        end
      end
    end
    

    使用第一种方法给读者没有指示最昂贵的物品是什么,只是它的价格是100.所有三种方法都要求读者认为夹具:expensive是最昂贵的物品fixtures/items.yml.粗心的程序员可以通过创建Itemin before(:all)或通过插入另一个fixture 来中断测试fixtures/items.yml.如果这是一个大文件,可能需要很长时间才能弄清问题是什么.

我开始做的一件事是#generate_random为我的所有模型添加一个方法.此方法仅在我运行规范时可用.例如:

class Item
  def self.generate_random(params={})
    Item.create(
      :name => params[:name] || String.generate_random,
      :price => params[:price] || rand(100)
    )
  end
end

(我这样做的具体细节实际上有点清晰.我有一个类来处理所有模型的生成和清理,但是这个代码对于我的例子来说足够清楚了.)所以在上面的例子中,我可能会测试为如下.佯装的警告:我的代码在很大程度上依赖于before(:all):

describe Item do
  describe '#most_expensive' do
    before(:all) do
      @items = []
      3.times { @items << Item.generate_random }
      @items << Item.generate_random({:price => 50})
    end

    it 'should return the most expensive item' do
      sorted = @items.sort { |a, b| b.price <=> a.price }
      expensive = Item.most_expensive
      expensive.should be(sorted[0])
      expensive.price.should >= 50      
    end
  end
end

这样,我的测试更好地揭示了令人惊讶的行为.当我以这种方式生成数据时,我偶尔偶然发现一个边缘情况,我的代码没有按预期运行,但如果我只使用灯具,我就不会抓住它.例如,#most_expensive如果我忘了处理多个项目共享最昂贵的价格的特殊情况,我的测试偶尔会在第一次失败should.看到AutoSpec中的非确定性故障会让我感到有些不对劲.如果我只使用灯具,发现这样的错误可能需要更长的时间.

我的测试也可以更好地在代码中演示预期的行为.我的测试清楚地表明,sorted是按价格按降序排序的项目数组.因为我希望#most_expensive它等于该数组的第一个元素,所以预期的行为更加明显most_expensive.

那么,这是一种不好的做法吗?我对固定装置的恐惧是不合理的吗?generate_random为每个模型编写一个方法太多了吗?或者这有效吗?



1> KeyserSoze..:

我很惊讶在这个主题中没有人或者杰森贝克与提到的 蒙特卡罗测试有关.这是我唯一一次广泛使用随机测试输入.然而,通过为每个测试用例提供随机数发生器的恒定种子,使测试可重复是非常重要的.



2> John Feminel..:

我们最近的一个项目对此进行了很多考虑.最后,我们确定了两点:

测试用例的可重复性至关重要.如果您必须编写随机测试,请准备好进行广泛的记录,因为如果/如果失败,您将需要确切知道原因.

使用随机性作为代码覆盖的拐杖意味着您要么没有良好的覆盖范围,要么您不了解域名足以知道代表性测试用例的构成.弄清楚哪个是真的并相应地修复它.

总之,随机性往往比它的价值更麻烦.在扣动扳机之前,请仔细考虑是否要正确使用它.我们最终决定随机测试案例一般都是个坏主意,如果有的话,可以谨慎使用.



3> Antti Tarvai..:

这是你第二点的答案:

(2)我使用测试作为代码的文档形式.如果我有硬编码的夹具值,很难揭示特定测试试图演示的内容.

我同意.理想情况下,规范示例本身应该是可以理解的.使用灯具是有问题的,因为它将示例的前提条件与其预期结果分开.

因此,许多RSpec用户已完全停止使用灯具.相反,在spec示例本身中构造所需的对象.

describe Item, "#most_expensive" do
  it 'should return the most expensive item' do
    items = [
      Item.create!(:price => 100),
      Item.create!(:price => 50)
    ]

    Item.most_expensive.price.should == 100
  end
end

如果结了大量的对象创建样板代码,你应该看看一些很多测试对象工厂库,如factory_girl,机械师,或FixtureReplacement.

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有