Iphone OCMock:为什么在尝试调用UIWebView模拟时会出现无法识别的选择器异常?
编辑:这都是由于“我的其他链接标志”设置中的输入错误造成的。有关更多信息,请参阅Iphone OCMock:为什么在尝试调用UIWebView模拟时会出现无法识别的选择器异常?,iphone,unit-testing,mocking,ocmock,google-toolbox-for-mac,Iphone,Unit Testing,Mocking,Ocmock,Google Toolbox For Mac,编辑:这都是由于“我的其他链接标志”设置中的输入错误造成的。有关更多信息,请参阅 我试图模拟UIWebView,以便在测试iOS视图控制器时验证是否调用了UIWebView上的方法。我使用的是一个OCMock静态库,它是从SVN修订版70(这是本问题提出时最新的版本)和Google Toolbox for Mac(GTM)单元测试框架(SVN修订版410)构建的。当视图控制器尝试调用预期的方法时,我遇到以下错误 Test Case '-[FirstLookViewControllerTests
我试图模拟UIWebView,以便在测试iOS视图控制器时验证是否调用了UIWebView上的方法。我使用的是一个OCMock静态库,它是从SVN修订版70(这是本问题提出时最新的版本)和Google Toolbox for Mac(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];
}
然而,当我添加了注释掉的期望值后,当使用部分模拟时返回了错误
我还有其他测试在同一个项目中成功地使用了mock
有什么想法吗?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模拟,当你试图做一些与它相关的事情时,它几乎总是会变得一团糟,比如将它添加到superview中。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模拟,当你尝试做一些与UIView相关的事情时,它几乎总是会变得一团糟,比如将它添加到superview中。这是一个一个字符关闭的问题,直到你看了几十遍才注意到
在OCMock论坛上,我已经将我的单元测试目标的其他链接器标志设置为
-ObjC-forceload$(PROJECT_DIR)/Libraries/libOCMock.a
。这是错误的<代码>-forceload应该是-force\u load
。一旦我修正了这个打字错误,我的测试就成功了。这是一个一个字符的问题,你在看了几十遍之后才注意到
在OCMock论坛上,我已经将我的单元测试目标的其他链接器标志设置为
-ObjC-forceload$(PROJECT_DIR)/Libraries/libOCMock.a
。这是错误的<代码>-forceload应该是-force\u load
。一旦我纠正了这个错误,我的测试就成功了。很抱歉,我还没有接受你的答案或对你的答案发表评论。经过一个漫长的周末,我刚回到工作岗位,今天晚些时候我就能测试这个了。你说得对,我给出的示例测试不需要模拟。我发布了一个新的样本测试,它确实需要模拟。我尝试使用viewController.view强制加载视图,但执行此操作时仍会出现相同的错误。很抱歉浪费您的时间-我的问题是我的其他链接器标志有误。我对你的答案投了赞成票,因为它提供了一个有用的观点,即我问题中的原始测试甚至不需要使用模拟测试。最好只在需要的情况下使用模拟。很抱歉,还没有接受或评论您的答案。经过一个漫长的周末,我刚回到工作岗位,今天晚些时候我就能测试这个了。你说得对,我给出的示例测试不需要模拟。我发布了一个新的样本测试,它确实需要模拟。我尝试使用viewController.view强制加载视图,但执行此操作时仍会出现相同的错误。很抱歉浪费您的时间-我的问题是我的其他链接器标志有误。我对你的答案投了赞成票,因为它提供了一个有用的观点,即我问题中的原始测试甚至不需要使用模拟测试。最好只在需要模拟的情况下使用模拟。