我的应用程序中有一些操作导致数据库中的多次插入,删除和更新。
今天我以这种方式测试它:
describe Checkout do
# Many lets and a before block are placed
# to create the context to my specs
it "creates the items" do
Checkout.call(params)
expect(Item.count).to eq(3)
end
it "set the invoice due date" do
Checkout.call(params)
expect(Invoices.last.due_date).to eq("2015-09-15".to_date)
end
# ... many other tests checking the database
end
问题在于每个“它”执行了许多繁重的“let”和“before”块。
我想准备上下文并检查很多事情而不会失去用自然语言描述这些测试的优势,或者至少提出任何改善事物的建议。
答案 0 :(得分:0)
TL; DR:很难
1) RSpec非常努力地确保测试数据不会从一个规范泄漏到另一个规范。如果没有,我们将很难在我们的测试中调试问题。
2) 我们希望有明确定义的规格。这为我们提供了有关故障的简单反馈,并作为系统的生动文档。这通常意味着我们每单位测试只有一个断言。
特别是在单元测试中,您可以通过尽可能地进行存根和模拟来加快速度。当Hash也能正常工作时,不要旋转一大堆记录。查看rspec-mocks,rr或其他存根宝石。
如果您正在使用工厂女孩,有时您可以使用FactoryGirl.build_stubbed
或FactoryGirl.build
而不是使用FactoryGirl.create
保存记录。此外,attributes_for
在功能和控制器规范中非常有用,因为它可以在不创建数据库对象的情况下为您提供属性哈希。
在您的规范中,我注意到您正在测试Checkout
但是在其他玩家(发票,物品)上进行断言。这些测试的测试不仅仅是Checkout。您可能会将其中的一部分存在并加快测试速度。
例如: 而不是验证Checkout是否创建了具有正确日期的新发票,以验证它是否只是将正确的消息发送到发票:
it "sets the invoice due date" do
expect(Invoices).to receive(:new).with({due_date: '2015-09-15'.to_date})
Checkout.call(params)
end
然而,这本身就很棘手,很容易发现自己测试过多的实现而不是行为。 (例如,我们想要一个发票,如果它是由.new,.generate,.build_invoices等创建的那么无关紧要)
您特别提到了集成测试:
集成测试还有一个缺点,即它们必须通过整个系统并且通常需要许多数据库记录,因此它们可能非常慢。 1&上面的2清楚地阻止了我们。
对于集成测试,我建议放松#2(上图)。不要害怕在集成测试中做出多个断言。它们应该来自用户的观点而且用户不止一件事。
最后,你必须找到一个平衡点。
你可以考虑做的一件事,特别是在集成测试中,是为你的规格添加故事,以使它们更具表现力:
RSpec.feature "Courses",
%q{
As a student,
I want to edit a listing of courses I'm involved in
So that I can change my schedule
},
:js do
老实说,集成测试是我发现设置时间过长特别麻烦的一个领域,我希望有更好的方法让多个测试共享相同的设置。我甚至试图为一组规范(即黑客)禁用数据库清理。
如果有其他人可以为这个特定问题提供更好的答案,我会很高兴。