2011-04-09 78 views
5

我正在使用Sinatra(1.2)和RSpec(2.5),並且想要創建一個具有屬性TDD樣式的新對象。這是最終的結果應該如何看起來像:Spec RSpec模型屬性設置器

class User 
    def initialize(name) 
    @name = name 
    end 
end 

我知道我有實施之前寫的例子,但我想在這裏解釋一下我的問題。 :)這是我迄今爲止沒有工作的規範:

describe User 
    it "creates a new user object" do 
    name = mock("A name") 
    user = mock(User) # shouldn't do this, see the reply's 
    user.should_receive(:name=).with(name) 
    User.new(name) 
    end 
end 

當我運行RSpec我得到「預期:1次,收到0次」錯誤。任何想法如何我可以解釋RSpec我想分配的名稱屬性?

注意:我沒有使用Rails,沒有使用ActiveRecord或其他任何東西,只是Ruby。

+1

供將來參考:嘲笑用戶對象不是一個好主意,我的不好。感謝所有的評論。 – Cimm 2011-04-09 09:14:14

回答

12

首先,讓我解釋一下爲什麼你寫的規格不工作:

您設定一個期望,通過mock(User)返回的模擬對象應該接受name=。這有兩個問題。首先模擬將不會收到任何東西,因爲它從來沒有被調用過。 mock(User)返回一個模擬對象,並且它不能用於設置類對象將接收的內容的期望值(僅做User.should_receive(...))。其次,即使您已對User類對象設置了期望值,該對象也將永遠不會收到name=。這也有兩個原因:第一,因爲name=(如果存在)將是一個實例方法,因此不會在類對象上調用,其次,您聲明沒有name=實例方法。你的代碼做的是它設置了一個實例變量。

現在,你應該如何爲此編寫一個測試?你不應該。測試是定義和聲明行爲,而不是實現。設置一個實例變量是純粹的實現。在你的示例代碼中沒有辦法從類的外部獲取實例變量的值,因此沒有理由爲它寫一個測試。

顯然你的代碼只是一個例子,任何有用的東西都會對@name變量做些什麼,這就是你應該測試的。首先編寫一個測試用於什麼User對象,然後編寫完成該測試所需的所有實現(但不再是)。編寫一個測試,反映該對象如何在實際生產代碼中使用。

+0

謝謝Theo。用戶模擬確實是非常錯誤的,我不應該這樣做。你說的和戴維一樣,我不應該測試實施,而應該保持更高的水平並測試行爲。 – Cimm 2011-04-09 09:20:16

1

你真的想嘲笑你正在開發的對象嗎?

require 'rspec' 

class User 
    attr_accessor :name 

    def initialize(name) 
    @name = name 
    end 
end 

describe User do 
    subject {User.new "other name"} 

    it "creates a new user object" do 
    subject.should respond_to :name= 
    end 
end 
+0

即使這讓我感覺太侵入規格。看到我的其他評論。 – 2011-04-09 08:25:45

+1

謝謝韋斯,這將是我的問題的litteral回答。閱讀David的回覆我想我看到了我的錯誤,應該以不同的方式處理。順便說一句,你對嘲笑的用戶類是正確的,不應該這樣做。 – Cimm 2011-04-09 09:04:35

5

我真的建議你不要使用模擬方法。這不是他們想要的。實際上,像這樣指定getter/setter並不是TDD的真正用處。這個想法是讓需求驅動setter/getters成爲現實。例如,有可能是該用戶的名稱出現在歡迎信息的要求時,他/她登錄,然後你會做這樣的事情:

describe 'login process' do 
    it "displays user's name after successful login" do 
    user = User.new("Cimm", "[email protected]", "secret") 
    post "/login", :email => "[email protected]", :password => "secret" 
    last_response.body.should =~ /Welcome Cimm/m 
    end 
end 

此規定的行爲,迫使你執行的手段設置name屬性(通過構造函數,在這種情況下)以及訪問它的方法。不需要直接指定構造函數。

+0

感謝大衛,不能與你爭論解決這個問題的最佳方式。 ;)我可以看到你的意思,是的,你是對的,我在這裏略過了幾步,應該先回到更高的層次。還有一些我不太感興趣......在某些時候,我將再次處於模型級別,並且我將不得不創建User.new方法,是否跳過當前的屬性分配,因爲它已經過測試視圖規範? – Cimm 2011-04-09 09:13:05