2011-12-30 29 views
13

我對這個單元測試有一個非常簡單的設置。我有了一個委託屬性的類:爲什麼我的單元測試中我的對象的弱委託屬性爲零?

@interface MyClass : NSObject 
... 
@property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate; 
... 
@end 

,我設置在我的測試委託:

- (void)testMyMethod_WithDelegate { 
    id delegate = mockDelegateHelper(); // uses OCMock to create a mock object 
    [[delegate expect] someMethod]; 
    myClassIvar.connectionDelegate = delegate; 
    [myClass someOtherMethod]; 
    STAssertNoThrow([delegate verify], @"should have called someMethod on delegate."); 
} 

但委託實際上並不在我的單元測試的3線設置,所以# someMethod永遠不會被調用。當我將其更改爲

myClassIvar.connectionDelegate = delegate; 
STAssertNotNil(myClassIvar.connectionDelegate, @"delegate should not be nil"); 

它在那裏失敗。我使用的是ARC,所以我的直覺是,這個弱財產被釋放。果然,將其更改爲strong會使STAssertNotNil通過。但我不希望與代表那樣做,我不明白爲什麼這裏有所作爲。從我讀到的,ARC中的所有本地參考文獻都是strongSTAssertNotNil(delegate)。爲什麼當局部變量中的同一個對象不是,我的弱委託屬性爲零?

回答

8

這是iOS運行時的錯誤。以下討論更詳細。簡而言之,iOS ARC運行時似乎無法處理對代理的弱引用。 OSX運行時可以。

http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252

據我從錯誤報告已經提交蘋果公司的討論明白。如果任何人有一個明智的解決方法...

+0

+1好極了,它似乎我[正確的想法](http://stackoverflow.com/a/9058542/31158)....感謝您找到正確的信息! – 2012-03-23 21:13:29

+0

您可能想嘗試iOS 6.0模擬器。如果弱/代理問題是一個運行時錯誤(它是),這可能會在iOS 6.0中解決。我對它進行了測試,但無法評論它(因爲它仍在NDA之下)。但你真的應該嘗試一下。真。 – Jelle 2012-06-27 12:19:10

1

我不是ARC專家,但我的猜測是mockDelegateHelper()正在返回一個弱對象。結果delegate在第二行代碼執行之前爲零。我冒昧猜測,無論是mockDelegateHelper()是罪魁禍首,還是OCMock正在如何操縱和創建對象。

+0

從流中刪除函數並沒有影響它,但是刪除OCMock解決了這個問題。我做了一個符合我的協議的顯式類,並用它來代替,而代表不再是零。這對我的測試是不幸的,但至少它回答了我的問題。謝謝。 – 2011-12-31 04:45:03

4

我真的不知道這裏發生了什麼,但OCMock返回從mockForProtocol:方法,我認爲這是正確的自動釋放NSProxy -descendant。也許ARC在NSProxies方面有問題?無論如何,我已經聲明變量__weak克服這個問題:

- (void)testMyMethod_WithDelegate { 
    // maybe you'll also need this modifier inside the helper 
    __weak id delegate = mockDelegateHelper(); 
    ... 

這真的沒有需要在這種情況下__strong(默認值),因爲它是自動釋放和你不保持它周圍。 ..

+0

哇,這只是爲我工作 – rodowi 2012-06-30 23:10:16

+0

任何暗示或解釋你想分享這個? – rodowi 2012-06-30 23:10:49

+1

@rodbot:好的,我只是認爲ARC在NSProxy的問題上存在問題,因爲這是OCMock使用的問題,通過用__weak聲明一個變量,你基本上告訴ARC不要打擾它。 – 2012-07-01 00:02:54

2

解決方法是使用部分模擬。

@interface TestMyDelegateProtocolDelegate : NSObject <MyDelegateProtocol> 
@end 

@implementation TestMyDelegateProtocolDelegate 
- (void)someMethod {} 
@end 


@implementation SomeTest { 
- (void)testMyMethod_WithDelegate { 
    id<MyDelegateProtocol> delegate = [[TestMyDelegateProtocolDelegate] alloc] init]; 
    id delegateMock = [OCMockObject partialMockForObject:delegate] 
    [[[delegateMock expect] someMethod] 
    myClassIvar.connectionDelegate = delegate; 
    [myClass someOtherMethod]; 
    STAssertNoThrow([delegate verify], @"should have called someMethod on delegate."); 
} 
@end 
+0

它適用於我作爲解決方法。 – 2012-08-21 15:33:22

+0

但並不完美。它需要包含來自其他類的依賴關係,而不是您正在測試的類 – 2012-08-21 16:00:05

+1

如果我以常規無痛方式執行'[OCMockObject mockForProtocol:@protocol(MyDelegateProtocol)]',那麼我是否也必須包含依賴項? – fabb 2012-08-22 13:21:36

相關問題