2010-11-11 23 views
1

編輯:這是由我的其他鏈接標誌設置中的拼寫錯誤造成的。有關更多信息,請參閱my answer belowOCMock:爲什麼我在嘗試調用UIWebView模擬時遇到無法識別的選擇器異常?


我試圖嘲笑一個UIWebView,以便我可以驗證它的方法在iOS視圖控制器的測試期間被調用。我正在使用一個由SVN修訂版70(這個問題最近的時間)構建的OCMock靜態庫,以及來自SVN的410版Google Toolbox for Mac(GTM)單元測試框架。當視圖控制器嘗試調用預期的方法時,出現以下錯誤。

Test Case '-[FirstLookViewControllerTests testViewDidLoad]' started. 
2010-11-11 07:32:02.272 Unit Test[38367:903] -[NSInvocation getArgumentAtIndexAsObject:]: unrecognized selector sent to instance 0x6869ea0 
2010-11-11 07:32:02.277 Unit Test[38367:903] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSInvocation getArgumentAtIndexAsObject:]: unrecognized selector sent to instance 0x6869ea0' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x010cebe9 __exceptionPreprocess + 185 
    1 libobjc.A.dylib      0x012235c2 objc_exception_throw + 47 
    2 CoreFoundation      0x010d06fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187 
    3 CoreFoundation      0x01040366 ___forwarding___ + 966 
    4 CoreFoundation      0x0103ff22 _CF_forwarding_prep_0 + 50 
    5 Unit Test       0x0000b29f -[OCMockRecorder matchesInvocation:] + 216 
    6 Unit Test       0x0000c1c1 -[OCMockObject handleInvocation:] + 111 
    7 Unit Test       0x0000c12a -[OCMockObject forwardInvocation:] + 43 
    8 CoreFoundation      0x01040404 ___forwarding___ + 1124 
    9 CoreFoundation      0x0103ff22 _CF_forwarding_prep_0 + 50 
    10 Unit Test       0x0000272a -[MyViewController viewDidLoad] + 100 
    11 Unit Test       0x0000926c -[MyViewControllerTests testViewDidLoad] + 243 
    12 Unit Test       0x0000537f -[SenTestCase invokeTest] + 163 
    13 Unit Test       0x000058a4 -[GTMTestCase invokeTest] + 146 
    14 Unit Test       0x0000501c -[SenTestCase performTest] + 37 
    15 Unit Test       0x000040c9 -[GTMIPhoneUnitTestDelegate runTests] + 1413 
    16 Unit Test       0x00003a87 -[GTMIPhoneUnitTestDelegate applicationDidFinishLaunching:] + 197 
    17 UIKit        0x00309253 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1252 
    18 UIKit        0x0030b55e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439 
    19 UIKit        0x0030aef0 -[UIApplication _run] + 452 
    20 UIKit        0x0031742e UIApplicationMain + 1160 
    21 Unit Test       0x0000468c main + 104 
    22 Unit Test       0x000026bd start + 53 
    23 ???         0x00000002 0x0 + 2 
) 
terminate called after throwing an instance of 'NSException' 
/Users/gjritter/src/google-toolbox-for-mac-read-only/UnitTesting/RunIPhoneUnitTest.sh: line 151: 38367 Abort trap    "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents 

我的測試代碼:

- (void)testViewDidLoad { 
    MyViewController *viewController = [[MyViewController alloc] init]; 

    id mockWebView = [OCMockObject mockForClass:[UIWebView class]]; 
    [[mockWebView expect] setDelegate:viewController]; 

    viewController.webView = mockWebView; 

    [viewController viewDidLoad]; 
    [mockWebView verify]; 
    [mockWebView release]; 
} 

我的視圖控制器代碼:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    webView.delegate = self; 
} 

我也覺得,如果我代替測試將成功運行:

- (void)testViewDidLoad { 
    MyViewController *viewController = [[MyViewController alloc] init]; 

    id mockWebView = [OCMockObject partialMockForObject:[[UIWebView alloc] init]]; 
    //[[mockWebView expect] setDelegate:viewController]; 

    viewController.webView = mockWebView; 

    [viewController viewDidLoad]; 
    [mockWebView verify]; 
    [mockWebView release]; 
} 

但是,只要我加入d被註釋掉的期望,使用部分模擬時返回的錯誤。

我有其他測試成功地在同一個項目中使用模擬。

任何想法?嘲笑OCMock支持的UIKit對象嗎?

編輯:基於下面的答案的建議,我嘗試了下面的測試,但我得到了同樣的錯誤:

- (void)testViewDidLoadLoadsWebView { 
    MyViewController *viewController = [[MyViewController alloc] init]; 
    UIWebView *webView = [[UIWebView alloc] init]; 

    // This test fails in the same fashion with or without the next line commented 
    //viewController.view; 

    id mockWebView = [OCMockObject partialMockForObject:webView]; 
    // When I comment out the following line, the test passes 
    [[mockWebView expect] loadRequest:[OCMArg any]]; 

    viewController.webView = mockWebView; 

    [viewController viewDidLoad]; 
    [mockWebView verify]; 
    [mockWebView release]; 
} 

回答

3

原來,這是一個字符問題,你沒有注意到,直到你已經看了幾十次。

在OCMock論壇上每this post,我已將我的單元測試目標的其他鏈接標記設置爲-ObjC -forceload $(PROJECT_DIR)/Libraries/libOCMock.a。這是錯誤的; -forceload應該是-force_load。一旦我解決了這個錯字,我的測試工作。

4

UIKit類是神祕莫測的,我已經發現,嘲笑它們可能會導致幾個小時的調試樂趣。也就是說,我發現只要有點耐心,你就可以使它工作。

我注意到你的代碼的第一件事就是你的控制器不會在你的測試中加載它的視圖。我通常確保在任何測試運行之前始終強制視圖加載。當然,這意味着你不能爲Web視圖的初始化編寫預期,但在這種情況下,你並不需要。你可以這樣做:

- (void)testViewDidLoadSetsWebViewDelegateToSelf { 
    MyViewController *viewController = [[MyViewController alloc] init]; 
    // Force the view to load 
    viewController.view; 

    assertThat(controller.webView.delegate, equalTo(controller)); 
} 

也就是說,如果你想隨後嘲笑Web視圖,我會建議使用部分模擬了現有Web視圖:

- (void)testWebViewDoesSomething { 
    MyViewController *viewController = [[MyViewController alloc] init]; 
    // Force the view to load 
    viewController.view; 

    id mockWebView = [OCMockObject partialMockForObject:controller.webView]; 
    [[mockWebView expect] someMethod]; 

    [controller doWhatever]; 

    [mockWebView verify]; 
} 

事實上,我發現最好總是對任何UIView子類使用部分模擬。如果你創建了一個UIView的完整模型,當你試圖做一些與之相關的視圖時,它幾乎總是會被混亂地炸燬,比如將它添加到超級視圖中。

+0

對不起,不接受或評論你的答案。我在一個漫長的週末後回到工作崗位,今天晚些時候就可以測試。 – Greg 2010-11-15 18:11:51

+0

你說得對,我給出的示例測試不需要模擬。我發佈了一個新的樣本測試,確實需要模擬。我嘗試使用viewController.view來強制視圖加載,但是當我這樣做時仍然會出現相同的錯誤。 – Greg 2010-11-16 02:14:10

+0

對不起,浪費你的時間 - 我的問題是我的其他鏈接標誌中的拼寫錯誤。我對你的回答提出了一個有用的觀點,即我的問題中的原始測試甚至不需要使用模擬。最好只在需要的地方使用mock。 – Greg 2010-11-16 03:15:23

相關問題