Rspec测试模型Scope响应:断言匹配失败及顺序校验问题
seen_between (Order & Type Mismatch) Let's break down why your test is failing and how to fix it properly:
The Root Cause
Your seen_between scope returns an ActiveRecord::Relation object (a lazy-loaded database query), not a plain Ruby array. When you use expect(seen_between).to eq([account3, account2]), RSpec is comparing an ActiveRecord::Relation instance to an Array instance—they'll never be equal, even if their underlying data matches.
Solution 1: Convert the Relation to an Array
The simplest fix is to call to_a on the relation to convert it into a plain array, then compare directly with your expected array (this enforces order):
describe "scope tests" do let(:account1) { create(:account, last_seen: Date.today)} let(:account2) { create(:account, last_seen: Date.today - 4.days)} let(:account3) { create(:account, last_seen: Date.today - 10.days)} let(:d) { Date.today} let(:seen_between) { Account.seen_between(d - 14.days, d - 2.days) } it "returns accounts in the correct order and excludes unwanted ones" do expect(seen_between.to_a).to eq([account3, account2]) expect(seen_between).to_not include(account1) end end
Solution 2: Use RSpec's match with ordered (No Array Conversion Needed)
If you prefer to keep the relation as-is (to avoid triggering the query earlier than necessary), you can use RSpec's match matcher combined with ordered to validate both the elements and their sequence:
it "returns accounts in the correct order and excludes unwanted ones" do expect(seen_between).to match([account3, account2]).ordered expect(seen_between).to_not include(account1) end
Why include Worked But Isn't Enough
The include matcher works because it checks if the elements exist in the relation (it doesn't care about type or order). But since you need to verify the order of results (which is part of your scope's expected behavior), you need a matcher that enforces sequence.
Bonus: Verify the Scope's SQL (Optional)
If you want an extra layer of validation (to ensure the scope is generating the right query), you can check the SQL output:
it "generates the correct SQL for the scope" do expect(seen_between.to_sql).to include("last_seen BETWEEN '#{(d -14.days).to_s(:db)}' AND '#{(d -2.days).to_s(:db)}'") end
内容的提问来源于stack exchange,提问作者bo-oz

