我对 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:Relation
计数和组成?
谢谢。
怎么样:
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
我认为问题在于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
...