我正在尝试在模型中测试我的默认范围行。
我的测试如下:
it 'orders by ascending name by default' do
expect(Coaster.scoped.to_sql).to eq Coaster.order(:name).to_sql
end
我的错误是:
expected: "SELECT \"coasters\".* FROM \"coasters\" ORDER BY name ASC, name"
got: "SELECT \"coasters\".* FROM \"coasters\" ORDER BY name ASC"
错误第一行末尾的, name
部分是什么意思,我该如何解决?
更新:
我的测试:
describe 'default scope' do
let!(:coaster_one) { FactoryGirl.create(:coaster, name: "Tower of Terror") }
let!(:coaster_two) { FactoryGirl.create(:coaster, name: "Apocalypse") }
it 'orders by ascending name' do
Coaster.all.should eq [:coaster_two, :coaster_one]
end
end
我的错误:
expected: [:coaster_two, :coaster_one]
got: [#<Coaster id: 5, name: "Apocalypse", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 408, created_at: "2013-07-23 20:48:52", updated_at: "2013-07-23 20:48:52", slug: "apocalypse-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>, #<Coaster id: 4, name: "Tower of Terror", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 407, created_at: "2013-07-23 20:48:52", updated_at: "2013-07-23 20:48:52", slug: "tower-of-terror-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>]
(compared using ==)
更新2:
看起来Rails 4不赞成使用default_scope,所以鉴于此,我已经从我的模型中删除了default_scope并将其替换为标准范围。
新范围现在是:
scope :by_name_asc, lambda { order("name ASC") }
我的相关测试是:
describe 'scopes' do
let!(:coaster_one) { FactoryGirl.create(:coaster, name: "Tower of Terror") }
let!(:coaster_two) { FactoryGirl.create(:coaster, name: "Apocalypse") }
it "orders coasters by ascending name" do
Coaster.by_name_asc.should eq [:coaster_two, :coaster_one]
end
end
运行此测试时,我得到:
1) Coaster scopes orders coasters by ascending name
Failure/Error: Coaster.by_name_asc.should eq [:coaster_two, :coaster_one]
expected: [:coaster_two, :coaster_one]
got: [#<Coaster id: 15, name: "Apocalypse", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 528, created_at: "2013-07-24 22:36:50", updated_at: "2013-07-24 22:36:50", slug: "apocalypse-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>, #<Coaster id: 14, name: "Tower of Terror", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 527, created_at: "2013-07-24 22:36:50", updated_at: "2013-07-24 22:36:50", slug: "tower-of-terror-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>]
(compared using ==)
Diff:
@@ -1,2 +1,2 @@
-[:coaster_two, :coaster_one]
+[#<Coaster id: 15, name: "Apocalypse", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 528, created_at: "2013-07-24 22:36:50", updated_at: "2013-07-24 22:36:50", slug: "apocalypse-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>, #<Coaster id: 14, name: "Tower of Terror", height: "60", speed: 60.0, length: "160", inversions: 4, material: nil, notes: nil, lat: nil, lng: nil, manufacturer_id: nil, park_id: 527, created_at: "2013-07-24 22:36:50", updated_at: "2013-07-24 22:36:50", slug: "tower-of-terror-at-alton-towers", style: nil, covering: nil, ride_style: nil, model: nil, layout: nil, order: nil, dates_ridden: nil, times_ridden: nil>]
# ./spec/models/coaster_spec.rb:10:in `block (3 levels) in <top (required)>'
关于出了什么问题的任何想法?
答案 0 :(得分:17)
测试默认范围的更好方法是使用具有预期输出的实际数据。为您的类创建虚拟对象,然后查询该类并将结果与您期望的正确顺序进行比较:
describe 'default scope' do
let!(:book_one) { Book.create(name: "The Count of Monte Cristo") }
let!(:book_two) { Book.create(name: "Animal Farm") }
it 'orders by ascending name' do
Book.all.should eq [book_two, book_one]
end
end
let!(:book_one)
创建Book
的实例,并将其分配给名为book_one
的局部变量。它的name
属性是基督山的计数。 let!(:book_two)
做了类似的事情。
如果默认顺序为name ASC
,则查询Book
模型应返回与book_two
的ActiveRecord关系作为第一个元素(“Animal ...”)和{{ 1}}作为第二个元素(“The C ...”)。
我们可以按如下方式测试这个期望:
book_one
这不会测试您的SQL,但会测试代码的直接输出,这更有用。它也与数据库无关。
答案 1 :(得分:3)
您的示例是将第二个订单字词添加到默认值,因此您将获得name ASC, name
。尝试首先使用reorder('')
剥离第一个订单子句,例如:
expect(Coaster.scoped.to_sql).to eq Coaster.reorder('').order('name ASC').to_sql
答案 2 :(得分:2)
最有可能的是,您将拥有多个具有类似默认范围的模型(如果没有,大多数情况下忽略此答案),因此您可以将此Rspec示例放入shared_example,您可以从各种模型中调用它规格。
我首选的检查默认范围的方法是确保默认的ActiveRecord::Relation
具有预期的子句(order
或where
或者不管情况如何),如下所示: / p>
<强>规格/支持/ shared_examples / default_scope_examples.rb 强>
shared_examples_for 'a default scope ordered by name' do
it 'adds an ordered by name clause' do
described_class.scoped.order_clauses.should include("name")
end
end
然后在您的Coaster
规范(以及具有相同默认范围的任何其他规范)中,您只需要:
<强>规格/模型/ coaster_spec.rb 强>
describe Coaster
it_behaves_like 'a default scope ordered by name'
# other spec examples #
end
最后,你可以看到这种模式如何扩展到各种默认范围,并保持干净,有条理,最重要的是,DRY。
答案 3 :(得分:0)
关于上次更新,应该是:
Coaster.all.should eq [coaster_two, coaster_one]
而不是:
Coaster.all.should eq [:coaster_two, :coaster_one]
答案 4 :(得分:0)
我们经常尝试使用工厂和实际值来测试范围。当我们只想确认范围设置正确时,我们会执行以下操作:
describe '.sorted' do
let(:nodes) { described_class.sorted.order_values }
let(:columns) { nodes.map { |n| n.instance_variable_get('@expr').name } }
it do
expect(columns)
.to eq [:service_type, :mri_type, :ct_slices, :mri_magnet_strength,
:created_at]
end
it { expect(nodes.map(&:direction)).to eq [:asc, :asc, :asc, :asc, :asc] }
end
这是对以下内容的测试:
scope :sorted, (
lambda do
order(:service_type, :mri_type, :ct_slices, :mri_magnet_strength,
:created_at)
end
)
答案 5 :(得分:0)
您可能会收到一些关于Mohamad答案的弃用警告,要解决,只需使用expect
和to
it 'orders by ascending name' do
expect(Book.all).to eq [book_two, book_one]
end