我刚开始测试,还不清楚什么时候应该使用let
。
我应该在下面的模型测试中使用let
来进行延迟加载吗?还是因为每个测试中的数据都有点不同,所以我可以保持原样?正如我在一些例子中看到的,它对控制器测试更为重要,因为:task
对每个动作测试都是相同的。
型号规格
require 'rails_helper'
RSpec.describe Task, type: :model do
describe "model validations" do
it "has a valid factory" do
expect(build(:task)).to be_valid
end
it "is invalid without executor" do
expect(build(:task, executor_id: nil)).not_to be_valid
end
it "is invalid without assigner" do
expect(build(:task, assigner_id: nil)).not_to be_valid
end
it "is invalid without content" do
expect(build(:task, content: nil)).not_to be_valid
end
it "is invalid without deadline" do
expect(build(:task, deadline: nil)).not_to be_valid
end
it "is invalid with deadline in the past" do
expect(build(:task, deadline: Faker::Time.between(DateTime.now - 1, DateTime.now - 2))).not_to be_valid
end
end
end
工厂
FactoryGirl.define do
factory :task do
content { Faker::Lorem.sentence }
deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
association :executor, factory: :user
association :assigner, factory: :user
end
end
let
的好处来自于与您使用的形式不同的测试。想象一下这个群体:
context "completing tasks" do
let(:completing_a_task){ task.complete }
context "that aren't due yet" do
let(:task){ create(:not_due_task) }
it "should not send an email" do
expect( TaskMailer ).not_to receive(:deliver_message)
expect{ completing_a_task }.not_to raise_error
end
end
context "overdue" do
let(:task){ create(:overdue_task) }
it "should send an email" do
expect( TaskMailer ).to receive(:deliver_message)
expect{ completing_a_task }.not_to raise_error
end
end
end
通过允许后期绑定,您可以进行最小的更改,但提供最大的覆盖范围。为了设置测试所需的适当行为,你需要的合作者越多,你就越有可能从let
中受益。虽然您不需要在测试套件中特别为DRY驱动,但测试的巨大设置块是一种气味,而let
技术是一个很好的工具,即使您的领域很复杂,也可以帮助您争取清晰和简单。我自己的例子中仍然没有合作者,但希望这个概念仍然足够清晰。
我建议保持原样,不要使用let
。不要担心DRYing你的测试。它们不相互交互,因此您不会遇到应用程序逻辑中的代码重复问题。
值得一提的是,您可以使用shoulda-matchers
gem来完成您所拥有的:https://github.com/thoughtbot/shoulda-matchers
describe Task do
describe "validations" do
it { is_expected.to validate_presence_of(:content) }
it { is_expected.to validate_presence_of(:deadline) }
end
end