testing a has_one relationship?
I have an object
class User < ActiveRecord::Base
has_one :subscription
end
and I have this test:
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
But I am getting an error:
1)
Spec::Mocks::MockExpectationError in 'User should increment shipped count when item_shipped'
Mock "Subscription_1113" received unexpected message :[]= with ("user_id", 922717357)
开发者_StackOverflow中文版./spec/models/user_spec.rb:29:
I am not sure how to mock this out and I can't seem to find any references to this kind of thing.
Instead of mocking Subscription, try stubbing out the methods on an actual Subscription instead:
subscription = Subscription.new
subscription.stub!(:item_shipped!)
subscription.stub!(:user_id)
@user.subscription = subscription
Mocks can be brittle. Any call to a mock must be anticipated and declared as an expectation. It doesn't appear that this particular test needs that model mocked in any case.
EDIT: Also remember to declare any return values that the calling class depends on. In your case this might look like:
subscription.stub!(:item_shipped!).and_return(true)
subscription.stub!(:user_id).and_return(@user.id)
etc.
Again, if you're not asserting that a method on your mocked model should be called, then the only thing mocking does here is make your test brittle. Mocks are meant for things like:
subscription.should_receive(:some_method).once
Otherwise you simply need to stub out methods that have undesirable side effects that don't concern your spec.
Setting up associations for tests is made easier with factories: (untested)
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
Of course you're not really testing the association here -- you're testing the item_shipped
method, which is what you really wanted.
change: mock_model(Subscription)
to mock_model(Subscription).as_null_object
which will allow for any messages to be sent to the object (assuming this is an acceptable behavior in your case)
精彩评论