bob*_*opy 6 ruby testing rspec fixtures
自从我开始使用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
Run Code Online (Sandbox Code Playgroud)
使用第一种方法给读者没有指示最昂贵的物品是什么,只是它的价格是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
Run Code Online (Sandbox Code Playgroud)
(我这样做的具体细节实际上有点清晰.我有一个类来处理所有模型的生成和清理,但是这个代码对于我的例子来说足够清楚了.)所以在上面的例子中,我可能会测试为如下.佯装的警告:我的代码在很大程度上依赖于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
Run Code Online (Sandbox Code Playgroud)
这样,我的测试更好地揭示了令人惊讶的行为.当我以这种方式生成数据时,我偶尔偶然发现一个边缘情况,我的代码没有按预期运行,但如果我只使用灯具,我就不会抓住它.例如,#most_expensive如果我忘了处理多个项目共享最昂贵的价格的特殊情况,我的测试偶尔会在第一次失败should.看到AutoSpec中的非确定性故障会让我感到有些不对劲.如果我只使用灯具,发现这样的错误可能需要更长的时间.
我的测试也可以更好地在代码中演示预期的行为.我的测试清楚地表明,sorted是按价格按降序排序的项目数组.因为我希望#most_expensive它等于该数组的第一个元素,所以预期的行为更加明显most_expensive.
那么,这是一种不好的做法吗?我对固定装置的恐惧是不合理的吗?generate_random为每个模型编写一个方法太多了吗?或者这有效吗?
我们最近的一个项目对此进行了很多考虑.最后,我们确定了两点:
总之,随机性往往比它的价值更麻烦.在扣动扳机之前,请仔细考虑是否要正确使用它.我们最终决定随机测试案例一般都是个坏主意,如果有的话,可以谨慎使用.
这是你第二点的答案:
(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
Run Code Online (Sandbox Code Playgroud)
如果结了大量的对象创建样板代码,你应该看看一些很多测试对象工厂库,如factory_girl,机械师,或FixtureReplacement.
| 归档时间: |
|
| 查看次数: |
2475 次 |
| 最近记录: |