簡體   English   中英

如何測試復合 Rails 模型范圍?

[英]How to test composite Rails model scopes?

考慮以下模型:

class Model < ActiveRecord::Base
  scope :a,       -> () { where(a: 1) }
  scope :b,       -> () { where(b: 1) }
  scope :a_or_b,  -> () { a.or(b) }
end

現在為了正確測試每個范圍,我至少會提供一個匹配的示例,而每個可能的變量都不匹配。 像這樣的東西:

RSpec.describe Model do
  describe "scopes" do
    describe ".a" do
      subject { Model.a }
      let!(:with_a_0) { create(:model, a: 0) }
      let!(:with_a_1) { create(:model, a: 1) }

      it { should_not include(with_a_0) }
      it { should     include(with_a_1) }
    end

    describe ".b" do
      subject { Model.b }
      let!(:with_b_0) { create(:model, b: 0) }
      let!(:with_b_1) { create(:model, b: 1) }

      it { should_not include(with_b_0) }
      it { should     include(with_b_1) }
    end

    describe ".a_or_b" do
      subject { Model.a_or_b }
      let!(:with_a_0_and_b_0) { create(:model, a: 0, b: 0) }
      let!(:with_a_0_and_b_1) { create(:model, a: 0, b: 1) }
      let!(:with_a_1_and_b_0) { create(:model, a: 1, b: 0) }
      let!(:with_a_1_and_b_1) { create(:model, a: 1, b: 1) }

      it { should_not include(with_a_0_and_b_0) }
      it { should     include(with_a_0_and_b_1) }
      it { should     include(with_a_1_and_b_0) }
      it { should     include(with_a_1_and_b_1) }
    end
  end
end

但是感覺就像我在.a_or_b測試中重新測試.a.b ,如果我再次.a_or_b它,使用另一個范圍,它會變得越來越大。

處理這個問題的明智方法是什么?

另外:這是單元測試還是集成測試?

這是一個艱難的。 我會說你必須在全面覆蓋和你的規范可讀性之間找到亞里士多德的平均值。 測試影響示波器行為方式的所有可能狀態的組合可能是不合理的。

它也不是真正的單元測試,因為它與 DB 層耦合。

我的方法是這樣的:

不要測試簡單的范圍(例如您的示例中的ab ),相信 AR 已經過良好測試,讓您的范圍名稱清晰並保留它。

在更復雜的范圍內,您可以顛倒編寫測試的方式:創建一次樣本,然后定義對不同范圍的期望(並使樣本名稱非常清晰,就像您已經在做的那樣)。

這將稍微減少規范的大小,並且更容易閱讀此類規范。 但是,如果您想對每個示波器進行全面覆蓋,它仍然會增加規格尺寸。

RSpec.describe Model do
  describe "scopes" do
    let!(:with_a_0_and_b_0) { create(:model, a: 0, b: 0) }
    let!(:with_a_0_and_b_1) { create(:model, a: 0, b: 1) }
    let!(:with_a_1_and_b_0) { create(:model, a: 1, b: 0) }
    let!(:with_a_1_and_b_1) { create(:model, a: 1, b: 1) }

    it { expect(described_class.a).to include(with_a_1_and_b_1).and include(with_a_1_and_b_1) }
    it { expect(described_class.a).not_to include(with_a_0_and_b_0) }

    # you get the idea

為了使這個^ 更具可讀性,我建議創建一個自定義 matcher ,您可以像這樣使用:

  it do 
    expect(described_class.a)
      .to retrieve(with_a_1_and_b_0, with_a_1_and_b_1)
      .and not_retrieve(with_a_0_and_b_0, with_a_0_and_b_1)
  end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM