Тестирование моделей со связями и обратными вызовами в Rails с RSpec и Factory_Girl - PullRequest
3 голосов
/ 02 июля 2010

Я все еще работаю над изучением RSpec, так что извините, если что-то упустил из виду ...

Я пишу тест для рецепта, в котором много ингредиентов. Ингредиенты фактически добавляются в процентах (с учетом общего столбца% в составе), поэтому я хочу убедиться, что общий столбец обновляется после каждого сохранения.

Итак, сейчас мой тест RSpec для модели recipe_ingredient выглядит примерно так:

it "should update recipe total percent" do
  @recipe = Factory.create(:basic_recipe)

  @ingredient.attributes = @valid_attributes.except(:recipe_id)
  @ingredient.recipe_id = @recipe.id
  @ingredient.percentage = 20
  @ingredient.save!

  @recipe.total_percentage.should == 20
end

У меня есть метод after_save, который просто вызывает быстрое обновление только что сохраненного ингредиента чека. Это очень просто:

РЕДАКТИРОВАТЬ: Это действие update_percentage в модели рецепта. Метод, который я вызываю после сохранения ингредиента, просто просматривает его рецепт и затем вызывает этот метод для него.

def update_percentage    
  self.update_attribute(:recipe.total_percentage, self.ingredients.calculate(:sum, :percentage))
end

Я что-то напутал? У меня нет доступа к родительскому объекту при выполнении тестов? Я попытался запустить базовый метод, чтобы просто изменить имя родительского рецепта после сохранения, но это не сработало. Я уверен, что это что-то в отношениях, которые я пропустил, но все отношения настроены правильно.

Спасибо за любую помощь / совет!

Ответы [ 3 ]

2 голосов
/ 02 июля 2010

Кстати, вы можете построить свой Ингредиент более понятным способом, так как вы уже используете factory_girl:

@ingredient = Factory(:ingredient, :recipe => @recipe, :percentage => 20)

Это создаст и сохранит Ингредиент.

2 голосов
/ 02 июля 2010

update_attribute для обновления атрибутов текущего объекта. Это означает, что вам нужно вызвать update_attribute для объекта, атрибут которого вы хотите обновить. В этом случае вы хотите обновить рецепт, а не ингредиент. Таким образом, вы должны позвонить recipe.update_attribute(:total_percentage, ...).

Кроме того, ингредиенты относятся к рецептам, а не к другим ингредиентам. Таким образом, вместо self.ingredients.sum(:percentage) вы действительно должны звонить recipe.ingredients.sum(:percentage).

Кроме того, вам необходимо перезагрузить @recipe перед тестированием total_percentage. Хотя он ссылается на ту же запись базы данных, что и @ingredient.recipe, он не указывает на тот же объект Ruby в памяти, поэтому обновления одного не появятся в другом. Перезагрузите @recipe, чтобы получить последние значения из базы данных после сохранения @ingredient.

0 голосов
/ 24 июля 2010

Привет, или вы поставили @ recipe.reload перед проверкой total_percentage на рецепт, или используйте ожидаемый.

 it "should update recipe total percent" do
  @recipe = Factory.create(:basic_recipe)
  expect {
   @ingredient.attributes = @valid_attributes.except(:recipe_id)
   @ingredient.recipe_id = @recipe.id
   @ingredient.percentage = 20
   @ingredient.save!
  }.to change(@recipe,:total_percentage).to(20)
end

Я бы рекомендовал взглянуть на эту презентацию.Много советов о новых и интересных вещах на rspec.http://www.slideshare.net/gsterndale/straight-up-rspec

ожидайте, что это псевдоним лямбда {}. Следует, и вы можете прочитать больше об этом здесь: rspec.rubyforge.org/rspec/1.3.0/classes/Spec/Matchers.html# M000168

...