测试has_one关系?

时间:2010-10-06 11:30:59

标签: ruby-on-rails rspec

我有一个对象

class User < ActiveRecord::Base
  has_one :subscription
end

我有这个测试:

  it "should increment shipped count when item_shipped" do
    @user.attributes = @valid_attributes
    @user.save

    subscription = mock_model(Subscription)
    subscription.stub!(:item_shipped!)
    subscription.stub!(:user_id)
    @user.subscription = subscription

    lambda{@user.item_shipped!}.should change{@user.shipped_count}.by(1)
  end

但是我收到了一个错误:

1)
Spec::Mocks::MockExpectationError in 'User should increment shipped count when item_shipped'
Mock "Subscription_1113" received unexpected message :[]= with ("user_id", 922717357)
./spec/models/user_spec.rb:29:

我不知道如何嘲笑这个,我似乎找不到任何关于此类事物的引用。

3 个答案:

答案 0 :(得分:2)

不要嘲笑Subscription,而是尝试在实际的Subscription上删除方法:

subscription = Subscription.new
subscription.stub!(:item_shipped!)
subscription.stub!(:user_id)
@user.subscription = subscription

模拟可能很脆弱。必须预期对模拟的任何调用并将其声明为期望。似乎这个特定测试似乎不需要在任何情况下模拟该模型。

编辑:还记得声明调用类所依赖的任何返回值。在您的情况下,这可能看起来像:

subscription.stub!(:item_shipped!).and_return(true)
subscription.stub!(:user_id).and_return(@user.id)

同样,如果你没有断言你的模拟模型上的方法应该被调用,那么这里唯一的模拟就是让你的测试变得脆弱。模拟适用于以下内容:

subscription.should_receive(:some_method).once

否则,您只需要找出与您的规范无关的具有不良副作用的方法。

答案 1 :(得分:0)

使用factories :(未经测试)

可以更轻松地设置测试关联
Factory.define :subscriber, :class => User do |f|
  f.name "Moe Howard"
  f.association :subscription, :factory => :subscription
end

Factory.define :subscription, :class => Subscription do |f|
end

it "should increment shipped count when item_shipped" do
  @user = Factory.create(:subscriber)
  lambda{@user.item_shipped!}.should change{@user.shipped_count}.by(1)
end

当然,你并没有真正测试这里的关联 - 你正在测试item_shipped方法,这正是你真正想要的。

答案 2 :(得分:0)

mock_model(Subscription)更改为mock_model(Subscription).as_null_object

允许将任何消息发送到对象(假设这是您可接受的行为)