ruby - 随机生成测试数据是一种不好的做法吗?

标签 ruby testing rspec fixtures

自从我开始使用 rspec 以来,我就对固定装置的概念产生了疑问。我主要关心的是:

  1. 我使用测试来揭示令人惊讶的行为。我并不总是足够聪明,可以为我正在测试的示例列举所有可能的边缘情况。使用硬编码的固定装置似乎有局限性,因为它只在我想象的非常具体的情况下测试我的代码。 (诚​​然,我的想象力也限制了我测试的案例。)

  2. 我使用测试作为代码文档的一种形式。如果我有硬编码的 fixture 值,就很难揭示特定测试试图展示的内容。例如:

    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。所有这三种方法都要求读者相信 fixture :expensivefixtures/items.yml 中列出的最昂贵的一个。一个粗心的程序员可能会通过在 before(:all) 中创建一个 Item 或通过将另一个 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 方法是否工作量太大?或者这行得通吗?

最佳答案

令我惊讶的是,这个主题或那个主题中没有人 Jason Baker linked to提及 Monte Carlo Testing .那是我唯一一次广泛使用随机测试输入。但是,通过为每个测试用例的随机数生成器提供恒定种子,使测试可重现非常重要。

关于ruby - 随机生成测试数据是一种不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/636353/

相关文章:

Ruby 基准测试模块 : meanings of "user", "system"和 "real"?

ruby - 如果将行推到 80 个字符以上,我是否应该不使用三元表达式?

ruby-on-rails - Rails 3.1,工厂女孩错误

python - `if __name__ == "__main_ _": ` 这样的成语有设计模式的名字吗?

ruby - 如何测试使用 rspec 的 block 的函数

ruby-on-rails - 脚手架生成的 rspec Controller 测试在工厂创建的模型上返回 nil

javascript - 从客户端测试 API

javascript - 与上下文无关的 JavaScript 测试框架

testing - Foundry 转换的 Python 单元测试?

rspec - 如何让rspec加载config.ru?