2013-07-29 44 views
4

我終於強加了一些TDD在我正在處理的一個項目上,並跑到邊緣......我知道我想要的代碼,但不知道如何測試吧:)OCMock測試一個對象被分配,並調用它的一個方法

我在尋找的實現是:

- (void) doSomething 
{ 
    FooBuilder *foo = [[FooBuilder alloc] init]; 
    [foo doSomethingElseWithCompletionBlock:^{ 
     [self somethingDone]; 
    }]; 
} 

所以我想我的測試來驗證)測試方法分配一個新的FooBuilder和b)該方法然後調用新對象的一種方法。

我該如何解決這個問題?我開始嘗試嘲笑類方法,但很快就確定了這條路是瘋狂的。

注意我沒有在這個測試中測試FooBuilder本身,只是在那裏進行了合作。

回答

1

通常情況下,依賴注入被用來提供一個完整的對象,說「而不是要求這個對象,在這裏你去使用這個。」但在這種情況下,我們希望能夠實例化一個新對象。所以我們不需要注入一個對象,而是注入這個類。 「而不是創建一個特定的類,在這裏你去實例化其中的一個。」

有兩種主要的依賴注入形式:「構造函數注入」(即使Objective-C將其分解爲分配和初始化)和「屬性注入」,我會堅持使用「構造函數」一詞。

對於構造函數注入,指定類在初始化:

- (instancetype)initWithFooBuilderClass:(Class)fooBuilderClass; 

對於財產注射,指定類的屬性:

@property (nonatomic, strong) Class fooBuilderClass; 

構造方法注入更清晰,因爲它使依賴明顯。但你可能更喜歡財產注入。有時我開始一種方式,重新思考另一種方式,改變我的想法。

無論使用哪種方式,您都可以使用默認初始值設定項,該默認初始值設定項將-initWithFooBuilderClass:或將屬性設置爲[FooBuilderClass class]

然後doSomething應該像這樣開頭:

- (void)doSomething 
{ 
    id foo = [[self.fooBuilderClass alloc] init]; 
    ... 
+0

喬恩,感謝您的關注和詳細的回覆 - 但我想我在這裏錯過了一些東西。你診斷被測試的類和'FooBuilder'類之間的耦合是問題。在這樣做的過程中,我覺得你正在簡化更復雜的事情。我有一個顯示Foos的對象Bar;要做到這一點,它需要用FooBuilder構建一個Foo。我覺得你要求我介紹一般性,我不需要僅僅爲了簡化測試。 – dpassage

+0

我今天早上醒來意識到問題實際上只是一個類的依賴注入。所以我完全重寫了我的答案。試試它的大小。 ...如果它仍然感覺過於複雜,讓我知道,我會嘗試進一步解釋。 –

+0

我仍然認爲你沒有得到我所要求的。我的問題是如何驅動OCMock API以確保我的被測對象正在進行正確的出站調用。你仍然試圖將普遍性注入一個不需要它的類中。 – dpassage

0

我最終加入了一類新的方法來FooBuilder這需要完成塊作爲參數解決該問題。所以我已經將實例化和方法調用從我的被測對象中移出到了協作者對象中。現在我可以嘲笑那個單一的類方法調用。

我認爲這最終會比我剛開始時的設計略好;現在需要有一個新的FooBuilder實例化的細節對類的用戶是隱藏的。這也很簡單。

它確實具有保持我的被測對象和FooBuilder類之間強大耦合的特性。也許這會讓我陷入困境 - 但我正在讓YAGNI打賭它不會。

+0

我很高興你發現有效的東西。但是你會在其他地方遇到同樣的問題,並需要藉助依賴注入。我在這裏給出另一個DI例子:http://stackoverflow.com/questions/13711911/unit-testing-example-with-ocunit/ –

+0

我相信我會的,這是一個很好的技術知道。但是,在這種情況下,它真的感覺就像增加了一般性會使代碼更難理解。感謝您的幫助 - 我已經在我的應用中使用了來自您網站的一些提示:) – dpassage

相關問題