14

我正在尝试在模型中测试我的默认范围线。

我的测试如下:

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)>'

关于出了什么问题的任何想法?

4

6 回答 6

20

测试默认范围的更好方法是使用具有预期输出的真实数据。为您的类创建虚拟对象,然后查询该类并将结果与​​您期望的正确顺序进行比较:

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模型应该返回一个 ActiveRecord 关系,book_two其中第一个元素(“Animal...”)和book_one第二个元素(“The C...”)。

我们可以如下测试这个期望:

Book.all.should eq [book_two, book_one]

这不会测试您的 SQL,但它会测试您的代码的直接输出,这更有用。它也是独立于数据库的。

于 2013-07-23T17:32:39.113 回答
3

您的示例是在默认值中添加二阶项,因此您得到name ASC, name. 尝试先用 剥离第一个顺序子句reorder(''),例如:

expect(Coaster.scoped.to_sql).to eq Coaster.reorder('').order('name ASC').to_sql
于 2013-07-23T17:32:21.643 回答
3

干掉它,使用共享示例

最有可能的是,您将拥有多个具有类似默认范围的模型(如果没有,则大多忽略此答案),因此您可以将此 Rspec 示例放入 shared_example 中,您可以从各种模型规范中调用它。

我检查默认范围的首选方法是确保默认ActiveRecord::Relation具有预期的子句(orderwhere任何情况),如下所示:

规范/支持/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。

于 2014-12-19T19:20:59.660 回答
0

关于最后一次更新,应该是:

Coaster.all.should eq [coaster_two, coaster_one]

代替:

Coaster.all.should eq [:coaster_two, :coaster_one]

于 2014-01-26T22:43:52.577 回答
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
  )
于 2015-08-05T15:40:16.237 回答
0

您可能会收到一些关于 Mohamad 答案的弃用警告,要解决,只需使用expectto

it 'orders by ascending name' do
  expect(Book.all).to eq [book_two, book_one]
end
于 2016-06-14T03:53:18.143 回答