Rspec Rails在find()之后模拟相关模型不起作用

时间:2010-08-30 20:16:19

标签: ruby-on-rails activerecord rspec

我有一些嵌套模型需要比标准accepts_nested_attributes_for逻辑多一点。而不是基于id键自动创建或更新子记录,在这种情况下,子记录必须已经存在并具有某些其他条件,否则会引发错误。

作为其中的一部分,我有一个父模型迭代给定的子属性并在匹配的子记录上调用#update_attributes。

我的问题是如何在父模型的规范中模拟#update_attributes。我想测试由给定属性标识的子记录实际上是接收#update_attributes

的那个

我的第一种方法是尝试mock_model,类似这样(不使用实际的模型名称,但为了清晰起见,只是'主题'和'儿童'):

before :each do
  subject.children = mock_model(Child), mock_model(Child), mock_model(Child)
  subject.save!
  @expected = subject.children[1]
  @input = {:child_id => @expected.id, :value => 'something'}
end

it 'should call #update_attributes on the child with given attributes' do
  @expected.should_receive(:update_attributes).
    with({:value => 'something'})
  subject.merge_children_attributes(@input)
end

但是,你实际上不能坚持模拟模型。并且出于同样的原因,您不能使用存根模型。我需要持久化记录,因为我在实现中使用children.find()children.all()。 (除非我嘲笑children关联,这似乎不对,因为它是一个主题的方法)。

然后我去了固定装置。

fixtures :children

before :each do
  subject.children = children(:one), children(:two), children(:three)
  subject.save!
  @expected = subject.children[1]
  @input = {:child_id => @expected.id, :value => 'something'}
end

it 'should call #update_attributes on the child with given attributes' do
  @expected.should_receive(:update_attributes).
    with({:value => 'something'})
  subject.merge_children_attributes(@input)
end

这里的问题是预期的匹配记录(@expected)从未收到:update_attributes - 任何内容。

大约puts,原因是当实现调用children.find()时,它会返回不同的实例而不是@expected = subject.children[1]规范。虽然:id属性是相同的。 ActiveRecord没有身份地图......

那么如何编写此规范才能通过?

更新

我确认在日志中查看正确的记录实际上正在更新。所以令人沮丧的是,我似乎无法模仿:update_attributes,因为find之间没有维护对象身份。

1 个答案:

答案 0 :(得分:0)

并不是一个令人满意的答案,但我通过规范的方法是删除Child.find(当您对子关联进行查找时是底层调用) - 返回一个模拟子项的数组我可以设定期望。所以:

before :each do
  @children = [ mock_model(Child), mock_model(Child), mock_model(Child) ]
  Child.should_receive(:find).and_return(@children)
  @expected= @children[1]
  @input = {:child_id => @expected.id, :value => 'something'}
end

it 'should call #update_attributes on the child with given attributes' do
  @expected.should_receive(:update_attributes).
    with({:value => 'something'})
  subject.merge_children_attributes(@input)
end

不是那么令人满意,因为在实现中只期望一个children.find(:all)似乎过于假设放入规范。不太可能,但是谁说不可能有一个调用多个children.find()的实现呢?