【问题标题】:Rspec Rails mocking associated model not working after find()Rspec Rails 模拟关联模型在 find() 后不起作用
【发布时间】:2010-08-30 20:16:18
【问题描述】:

我有一些嵌套模型需要比标准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,因为在 finds 之间没有维护对象身份。

【问题讨论】:

    标签: ruby-on-rails activerecord rspec


    【解决方案1】:

    并不是一个真正令人满意的答案,但我为传递规范所做的只是将 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()s 的实现呢?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多