簡體   English   中英

OCMock:為什么在嘗試調用UIWebView模擬時會出現無法識別的選擇器異常?

[英]OCMock: Why do I get an unrecognized selector exception when attempting to call a UIWebView mock?

編輯:這都是我其他鏈接標志設置中的錯字引起的。 有關更多信息,請參見下面答案


我正在嘗試模擬UIWebView,以便可以驗證在測試iOS視圖控制器期間是否調用了其中的方法。 我使用的是從SVN修訂版70(此問題發布時的最新版本)構建的OCMock靜態庫,以及Google工具箱(Mac版)的Google工具箱(GTM),從SVN修訂版410。 當視圖控制器嘗試調用期望的方法時,出現以下錯誤。

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];
}

但是,一旦添加了被注釋掉的期望,使用部分模擬時就會返回錯誤。

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

有任何想法嗎? 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];
}

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的完整模型,則在嘗試執行與視圖相關的操作(例如將其添加到超級視圖)時,幾乎總是會混亂地崩潰。

事實證明,這是直到您看了幾十遍才發現的一個字符問題。

根據OCMock論壇上的此帖子 ,我已將我的單元測試目標的“其他鏈接器標志”設置為-ObjC -forceload $(PROJECT_DIR)/Libraries/libOCMock.a 這是錯誤的; -forceload應該是-force_load 一旦我解決了這個錯字,我的測試就可以了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM