3

我仍在努力学习 RSpec,所以如果完全忽略了某些东西,我很抱歉......

我正在为包含许多成分的食谱编写测试。成分实际上是按百分比添加的(配方中有一个总百分比列),所以我想确保每次保存后总列更新。

所以现在我对 recipe_ingredient 模型的 RSpec 测试是这样的:

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

我在搞砸什么吗?运行测试时我无权访问父对象吗?我尝试运行一种基本方法来在保存后更改父配方名称,但这没有用。我确定这是我忽略的关系中的某些东西,但所有关系都设置正确。

感谢您的任何帮助/建议!

4

3 回答 3

2

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

于 2010-07-01T20:35:09.303 回答
2

顺便说一句,您可以以更清晰的方式构建您的成分,因为您已经在使用 factory_girl:

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

这将构建并保存一个成分。

于 2010-07-01T21:28:19.930 回答
0

嘿,或者你在检查食谱的总百分比之前放一个@recipe.reload,或者使用期望。

 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

expect 是 lambda{}.should 的别名,您可以在此处阅读更多信息:rspec.rubyforge.org/rspec/1.3.0/classes/Spec/Matchers.html#M000168

于 2010-07-23T20:02:21.467 回答