Rails 3 и Rspec: столбец кеша счетчика обновляется до 2, когда ожидается 1

Я тестирую с Rspec модель под названием Solutions, которая имеет много лайков. Решение хранит, сколько у него лайков (counter_cache). Он имеет атрибут «likes_count» (и соответствующее поле базы данных).

Когда я создаю запись «Мне нравится», связанную с решением, я ожидаю, что атрибут решения «likes_count» должен быть обновлен с нуля до 1. Когда я делаю это в консоли, это работает.

Но когда я запускаю спецификацию, делая ТО ЖЕ ДЕЛО, что и в консоли, она ДВАЖДЫ обновляет поле «likes_count», устанавливая для него значение 2.

Взгляните (в консоли) РАБОТАЕТ:

irb(main):001:0> solution = Factory(:solution)
irb(main):004:0> solution.likes_count 
=> nil
irb(main):006:0> like = Factory(:like, :likeable => solution)
=> #<Like id: 1, user_id: 2, likeable_id: 1, likeable_type: "Solution", 
   created_at: "2011-11-23 19:31:23", updated_at: "2011-11-23 19:31:23">
irb(main):007:0> solution.reload.likes_count
=> 1

Взгляните на результат спецификации НЕ РАБОТАЕТ:

 1) Solution counter cache should be increased when a like is created
 Failure/Error: subject.reload.likes_count.should be 1

   expected #<Fixnum:3> => 1
        got #<Fixnum:5> => 2

   Compared using equal?, which compares object identity,
   but expected and actual are not the same object. Use
   'actual.should == expected' if you don't care about
   object identity in this example.
 # ./spec/models/solution_spec.rb:45:in `block (3 levels) in <top (required)>'

Вот спецификация:

describe "counter cache" do
  let(:solution) { Factory(:solution) }

  it "should be increased when a like is created" do
    Factory(:like, :likeable => solution)
    solution.reload.likes_count.should be 1
  end
end  

Я взглянул на test.log и понял, что запрос БД, который обновляет столбец кеша счетчика, вызывался в тесте два раза.

  SQL (0.5ms)  INSERT INTO "likes" ("created_at", "likeable_id", "likeable_type", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?)  [["created_at", Wed, 23 Nov 2011 19:38:31 UTC +00:00], ["likeable_id", 121], ["likeable_type", "Solution"], ["updated_at", Wed, 23 Nov 2011 19:38:31 UTC +00:00], ["user_id", 204]]
  SQL (0.3ms)  UPDATE "solutions" SET "likes_count" = COALESCE("likes_count", 0) + 1 WHERE "solutions"."id" IN (SELECT "solutions"."id" FROM "solutions" WHERE "solutions"."id" = 121 ORDER BY id DESC)
  SQL (0.1ms)  UPDATE "solutions" SET "likes_count" = COALESCE("likes_count", 0) + 1 WHERE "solutions"."id" IN (SELECT "solutions"."id" FROM "solutions" WHERE "solutions"."id" = 121 ORDER BY id DESC)
  Solution Load (0.3ms)  SELECT "solutions".* FROM "solutions" WHERE "solutions"."id" = ? LIMIT 1  [["id", 121]]

person Bruno Dias    schedule 23.11.2011    source источник


Ответы (2)


У меня такая же проблема. Оказалось, что мой spec_helper.rb загружал модели во второй раз и, следовательно, создавал второй обратный вызов для обновления счетчиков. Убедитесь, что ваша модель решения не перезагружается другим процессом.

Ответ выше также правильный: вам нужно использовать == вместо be для сравнения, но это не исправит множественные обновления, которые вы видите в файле журнала.

person jkronz    schedule 29.11.2011
comment
Да, это была проблема. Большое спасибо, jkronz! Этот фрагмент вызывал проблему в блоке Spork.each_run: Dir["#{Rails.root}/app/**/*.rb"].each { |f| load f } - person Bruno Dias; 19.04.2012
comment
У меня такая же проблема, но я не могу найти, где он загружается дважды. Любые предложения о том, как отладить это? Я использую рельсы 4.1. Спасибо. - person Ryan-Neal Mes; 03.09.2014

У вас есть ответ в ваших журналах:

  • Когда вы используете be, он сравнивает object_id, который всегда один и тот же для пары объектов, таких как true и 1. id из 1 выглядит как 2. Попробуйте в консоли: 1.object_id #=> 2

  • Поэтому замените свой тест на: solution.reload.likes_count.should eql 1 или даже solution.reload.likes_count.should == 1

person apneadiving    schedule 23.11.2011