【问题标题】:Testing ActiveRecord:Relation count and composition (members and their order)测试 ActiveRecord:关系计数和组成(成员及其顺序)
【发布时间】:2012-11-19 19:51:57
【问题描述】:

我对 Rspec 很陌生,所以在编写一些搜索结果预期时,我偶然发现了一个意外行为:

describe "resultset" do

  subject { search.products }

    describe "product name has a higher weight than product description" do

      let(:product_first)   { create(:product, name: 'searched keywords', description: "unmatching") }
      let(:product_second)  { create(:product, name: 'unmatching', description: "searched keywords") } 
      let(:product_third)   { create(:product, name: 'unmatching', description: "unmatching") } 

      let(:search) { create(:search, keywords: "searched keywords") }

      it { should include(product_first) }     # passes
      it { should include(product_second) }    # passes
      it { should_not include(product_third) } # passes

      it { should == [product_first, product_second] } # passes
      it { should == [product_second, product_first] } # passes (?!?)
      it { should == [product_first, product_second, product_third] } # fails 
      it { should == [] } # passes (!) 

      specify { subject.count.should == 2 }   # fails => got 0
      specify { subject.count.should eq(2) } # fails => got 0
  end 
end

如何解释这种行为?

如何测试search.products.count 应该是2

如何测试search.products 应该是[product_first, product_second]

换句话说,如何测试ActiveRecord:Relationcountcomposition

谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 rspec rspec2 rspec-rails


    【解决方案1】:

    怎么样:

    it { should have(2).items }
    

    因为您的主题是 search.products 并且由于 let 的工作方式(它仅在调用时创建变量),您可能希望强制创建您的第一个、第二个和第三个产品。只需将let(...) 行更改为let!(...)

    所以工作(和连贯的)规范是:

      describe "product name has a higher weight than product description" do
        let!(:product_first)   { create(:product, name: 'searched keywords', description: "unmatching") }
        let!(:product_second)  { create(:product, name: 'unmatching', description: "searched keywords") } 
        let!(:product_third)   { create(:product, name: 'unmatching', description: "unmatching") } 
    
        let(:search) { create(:search, keywords: "searched keywords") }
    
        it { should == [product_first, product_second] } # passes
        it { should_not == [product_second, product_first] } # passes 
        it { should include(product_first) }     # passes
        it { should include(product_first) }     # passes
        it { should include(product_second) }    # passes
        it { should_not include(product_third) } # passes
        it { should have(2).items }   # passes
      end
    

    【讨论】:

      【解决方案2】:

      我认为问题在于let 的工作方式。当您使用let 定义变量时,它实际上不会被评估,直到您在其中一个测试中引用它。因此,在您运行 search.products! 之前,您实际上不会创建 product_first 对象!

      我认为你可以通过使用before 来获得你想要的东西,并将所有测试对象实例化为实例变量。比如:

      describe "resultset" do
      
        describe "product name has a higher weight than product description" do
      
          before(:each) do
            @product_first = create(:product, name: 'searched keywords', description: "unmatching")
            @product_second = create(:product, name: 'unmatching', description: "searched keywords")
            @product_third = create(:product, name: 'unmatching', description: "unmatching")
            @search = create(:search, keywords: 'searched keywords')
          end
      
          subject {@search.products}
          it { should include(@product_first) }     # passes
          ...
      

      【讨论】:

      • 您对let 的工作方式是正确的,这就是问题所在! (对我来说,直到现在我才知道它的问题)...我能够修复我的测试,只需将let 更改为let!,遵循@Jason 的建议,并强制创建产品。
      猜你喜欢
      • 2021-07-29
      • 2020-04-20
      • 1970-01-01
      • 2016-06-16
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      • 1970-01-01
      相关资源
      最近更新 更多