Ruby on rails 测试一个有一个关系吗?

Ruby on rails 测试一个有一个关系吗?,ruby-on-rails,rspec,Ruby On Rails,Rspec,我有一个目标 class User < ActiveRecord::Base has_one :subscription end 但我得到了一个错误: 1) Spec::Mocks::MockExpectationError in 'User should increment shipped count when item_shipped' Mock "Subscription_1113" received unexpected message :[]= with ("user_id

我有一个目标

class User < ActiveRecord::Base
  has_one :subscription
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:

我不知道如何模拟这一点,我似乎找不到任何关于这类事情的引用。

与其模拟订阅,不如尝试在实际订阅上删除方法:

subscription = Subscription.new
subscription.stub!(:item_shipped!)
subscription.stub!(:user_id)
@user.subscription = subscription
模拟可能很脆弱。对mock的任何调用都必须是预期的,并声明为预期。在任何情况下,该特定测试似乎都不需要模拟该模型

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

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

同样,如果您没有断言应该调用模拟模型上的方法,那么模拟在这里所做的唯一事情就是使测试变得脆弱。模拟用于以下用途:

subscription.should_receive(:some_method).once

否则,您只需剔除那些具有与您的规范无关的不良副作用的方法。

设置测试关联会更容易:(未测试)

当然,您并不是在这里真正测试关联——您是在测试您真正想要的
item\u方法。

更改:
mock\u模型(订阅)
mock\u模型(订阅)。作为\u null\u对象


这将允许向对象发送任何消息(假设在您的情况下这是一种可接受的行为)

谢谢。。。这似乎不起作用,但这可能是因为装运的物品的内部工作!我确实需要模拟订阅,因为它是从我正在测试的方法中调用的。是的,如果不知道方法的细节,很难说。请记住,模拟旨在用于创建特定的期望。换句话说,如果您的规范不会断言将调用模拟对象上的某个方法,那么就没有必要模拟该对象。只需在对象的真实实例上删除任何方法,这些方法将调用繁重或其他非必需/不需要的操作。正如Martin Fowler所指出的,mock不是存根:还请记住,如果用户希望在User#item_shipped!(已发货)的内部订阅中返回值!,您需要在stubbed方法上设置返回值(请参见编辑)。用户项目_已发货!方法调用subscription(除了做其他事情之外),这就是我需要模拟它的原因。
subscription.should_receive(:some_method).once
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