2011-01-14 66 views
1

我想用單元測試來驗證我的控制器類中的所有IBoutlet都正確地連接在NIB文件中。我想用OCMock做到這一點 - 即使我知道我可以簡單地斷言加載NIB後控制器變量不是nil。這更多的是對這個過程如何工作的一般理解 - 就我所知,這也應該是有效的。檢查IBOutlet與OCMock的連接

The NIB OnOffSwitchCell作爲其檔案負責人OnOffSwitchCellController。 這是我的測試方法:

- (void) testIBOutletCellIsWiredToXib { 
    id mockController = [OCMockObject mockForClass:[OnOffSwitchCellController class]]; 
    [[mockController expect] awakeAfterUsingCoder:OCMOCK_ANY]; 
    [[mockController expect] setValue:OCMOCK_ANY forKey:@"cell"]; 
    [[mockController expect] setValue:OCMOCK_ANY forKey:@"thelabel"]; 
    [[mockController expect] setValue:OCMOCK_ANY forKey:@"theswitch"]; 

    NSArray* nibContents = [guiBundle loadNibNamed:@"OnOffSwitchCell" 
              owner:mockController 
              options:nil]; 
    assertThat(nibContents, isNot(nil)); 
    assertThatInt([nibContents count], is(equalToInt(1))); 
    assertThat([nibContents objectAtIndex:0], is(instanceOf([OnOffSwitchCell class]))); 

    [mockController verify]; 
} 

guiBundle存在並被證明是有效的一個NSBundle對象。

據我所知,loadNibNamed:owner:options:將反序列化NIB中的對象,調用awakeAfterUsingCoder:,然後通過調用setValue:forKey:爲每個對象設置出口。

我放了三個斷言,以確保加載的NIB實際上包含正確的對象 - 當我放入實際控制器的實例時,這些通過確定。但是當我如上所示使用模擬時,它甚至沒有達到這個目標。相反,測試崩潰與此:

 
Test Case '-[OnOffSwitchCellControllerTestCase testIBOutletCellIsWiredToXib]' started. 
2011-01-14 10:48:35.364 GTMTest[67797:903] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', 
    reason: 'OCMockObject[OnOffSwitchCellController]: 
       unexpected method invoked: awakeAfterUsingCoder:<UINibDecoder: 0x500e800> 
    expected: setValue:<OCMAnyConstraint: 0x4c718e0> forKey:@"cell" 
    expected: setValue:<OCMAnyConstraint: 0x4c71ce0> forKey:@"thelabel" 
    expected: setValue:<OCMAnyConstraint: 0x4c71ed0> forKey:@"theswitch"' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x00e3dbe9 __exceptionPreprocess + 185 
    1 libobjc.A.dylib      0x00f925c2 objc_exception_throw + 47 
    2 CoreFoundation      0x00e3db21 -[NSException raise] + 17 
    3 GTMTest        0x0001a049 -[OCMockObject handleUnRecordedInvocation:] + 322 
    4 GTMTest        0x00019aca -[OCMockObject forwardInvocation:] + 77 
    5 CoreFoundation      0x00daf404 ___forwarding___ + 1124 
    6 CoreFoundation      0x00daef22 _CF_forwarding_prep_0 + 50 
    7 UIKit        0x0062394a UINibDecoderDecodeObjectForValue + 2438 
    8 UIKit        0x00624693 -[UINibDecoder decodeObjectForKey:] + 398 
    9 UIKit        0x0053cf43 -[UIRuntimeConnection initWithCoder:] + 212 
    10 UIKit        0x0053d4b1 -[UIRuntimeEventConnection initWithCoder:] + 64 
    11 UIKit        0x006239e4 UINibDecoderDecodeObjectForValue + 2592 
    12 UIKit        0x006232dc UINibDecoderDecodeObjectForValue + 792 
    13 UIKit        0x00624693 -[UINibDecoder decodeObjectForKey:] + 398 
    14 UIKit        0x0053c200 -[UINib instantiateWithOwner:options:] + 804 
    15 UIKit        0x0053e081 -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 168 
    16 GTMTest        0x000140dc -[OnOffSwitchCellControllerTestCase testIBOutletCellIsWiredToXib] + 503 
    17 GTMTest        0x000041f3 -[SenTestCase invokeTest] + 163 
    18 GTMTest        0x0000479a -[GTMTestCase invokeTest] + 146 
    19 GTMTest        0x00003e90 -[SenTestCase performTest] + 37 
    20 GTMTest        0x00002f3d -[GTMIPhoneUnitTestDelegate runTests] + 1413 
    21 GTMTest        0x000028fb -[GTMIPhoneUnitTestDelegate applicationDidFinishLaunching:] + 197 
    22 UIKit        0x00347253 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1252 
    23 UIKit        0x0034955e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439 
    24 UIKit        0x00348ef0 -[UIApplication _run] + 452 
    25 UIKit        0x0035542e UIApplicationMain + 1160 
    26 GTMTest        0x00003500 main + 104 
    27 GTMTest        0x0000273d start + 53 
    28 ???         0x00000002 0x0 + 2 
) 
terminate called after throwing an instance of 'NSException' 

所以它是抱怨調用awakeAfterUsingCoder:爲意外,即使我清楚地預期了。

我也嘗試刪除該期望,並用一個不會報告多餘方法調用的很好的模擬替換模擬,但它仍然中止並報告setValue:forKey:未被調用。

我在這裏錯過了什麼?

回答

0

你有沒有試過在主系統線程上運行這個?你不能在主線程中實例化UIKit類。不知道GTM是怎麼做的,而是用GHUnit你可以把下面的到你的測試用例類:

- (BOOL)shouldRunOnMainThread { 
    /* Tell GHUnit to run on a separate thread */ 
    return YES; 
} 
+0

不幸的是,沒有什麼區別。 – 2011-03-04 13:16:40

-1

你不能真正做任何視覺的東西,在單元測試。視圖從未實際加載。此外,你不需要測試awakeAfterUsingCoder被調用。這就是蘋果的東西。通常你的單元測試只能測試你的邏輯。您可以放心地認爲awakeAfterUsingCoder是從init調用的,因爲它是Apple的代碼。你只需要確保你的方法被調用