RSpec:Let 语句有时会出现问题,因为当我执行 get 请求时我需要它们的值存在于数据库中

RSpec: Let statements sometimes an issue as I need their values to exist in the database when I perform a get request

假设我有以下 RSpec 请求测试:

RSpec.describe Api::OrdersController, type: :request do  
  let(:customer) { FactoryGirl.create(:customer) }
  let(:order_1) { FactoryGirl.create(:order, customer: customer) }
  let(:order_2) { FactoryGirl.create(:order, customer: customer) }

  describe "GET #index" do
    it "responds with all the orders of the customer" do
      get customer_orders_path(id: customer.id)
      expect(json_body.count).to eq(2)
    end
  end

我在这个测试中遇到的问题是它失败了,这是由于 let 语句的惰性计算导致测试数据库中不存在任何订单。

解决这个问题的一种方法是使用实​​例变量。然而,问题是我有很多测试都在使用这些 let 语句而没有任何问题,而且对于几个测试来说似乎不合理,其中惰性评估是一个障碍,我必须将我拥有的所有 let 语句重构为实例变量。此外,我有许多 let 语句(大约 20 个),因此将 let 语句和实例变量都保留在 before 语句中并根据情况使用它们的潜在想法将难以管理。

所以我目前看到的唯一解决方案是完全放弃 let 语句。但我希望有更好的选择,因为 let 语句被广泛认为是其可重用性和效率的最佳实践。

有没有我想念的更好的解决方案?有没有办法在执行 get 请求之前触发 let 语句的评估? (尽管这似乎又是一个肮脏的解决方法..)

如果您不想重构任何东西,那么一个选项是使用 let!

Here is a good explanation for let, let!.

let!(:order_1) { FactoryGirl.create(:order, customer: customer) }
let!(:order_2) { FactoryGirl.create(:order, customer: customer) }

就我个人而言,我会像这样进行测试:

describe Api::OrdersController, type: :controller do  
  let(:customer) { create(:customer) }

  describe "GET #index" do
   it "responds with all the orders of the customer" do
     create_list(:order, 2, customer: customer)
     get customer_orders_path(id: customer.id)
     expect(json_body.count).to eq(2)
   end
  end
end

我通常会尽量避免 let! 因为测试需要不同的东西出现在数据库中,我不想创建超出需要的东西。或者,如果我可以使用存根(build_stubbed,等等),那将是我的第一选择。