2010-10-06 114 views
4

我有一個對象測試has_one關係?

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: 

我不知道如何嘲笑了這一點,我似乎無法找到任何這類事情的參考。

回答

2

而是嘲諷認購,嘗試在實際認購捻熄了方法,而不是:

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 

否則,你只需要存根出有不良副作用,不關心你的規範方法。

+0

謝謝...這似乎不工作,但這可能是因爲item_shipped的內部工作原因!我確實需要模擬訂閱,因爲它是從我正在測試的方法中調用的。 – phil 2010-10-07 13:17:13

+1

是的,如果不知道方法的細節,很難說。請記住,mock旨在用於創建特定的期望。換句話說,如果你的規範不會斷言某個模擬對象上的某個方法會被調用,那麼就沒有必要嘲笑那個對象。只需將任何方法存入實際的對象實例中,以調用沉重的操作或其他不需要的操作。正如Martin Fowler指出的那樣,mock不是存根:http://martinfowler.com/articles/mocksArentStubs.html – 2010-10-07 19:14:32

+0

還要記住,如果用戶希望在用戶#item_shipped!內部的訂閱中返回值,需要在存根方法上設置返回值(請參閱編輯)。 – 2010-10-07 19:19:49

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方法,這就是你真的很想。

+0

有趣的,我會試試這個。用戶item_shipped!方法調用訂閱(其他事情),這就是爲什麼我需要嘲笑它。 – phil 2010-10-07 13:19:16

0

變化:mock_model(Subscription)mock_model(Subscription).as_null_object

,這將允許任何消息要發送到的物體(假設這是你的情況可以接受的行爲)