rspec 模型规格对比工厂

rspec model spec let vs factory

我刚开始测试,我不太清楚什么时候应该使用 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。不要担心让你的测试变干。它们彼此不交互,因此您不会 运行 陷入应用程序逻辑中代码重复的问题。

对于它的价值,您可以使用 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

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 技术是帮助争取清晰度和简单性的好工具,即使在您的领域呈现出复杂性。我自己的例子仍然没有合作者,但希望这个概念仍然足够清楚。