我想通过单元测试验证我的控制器类中的所有IBoutlet
都已正确连接到NIB文件中。我想用OCMock做这个 - 尽管我知道我可以在加载NIB之后断言控制器变量不是nil
。这更多地是对过程如何运作的一般理解 - 据我所知,这也应该有效。
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实际上包含正确的对象 - 当我放入真实控制器的实例时,这些传递OK。但是当我使用上面显示的模拟时,它甚至都没有达到这个目的。相反,测试崩溃了:
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 :(得分:0)
您是否尝试在主系统线程上运行此功能?你不能在主线程上实例化UIKit类。不确定GTM是如何做到的,但是使用GHUnit,您可以将以下内容放入测试用例类中:
- (BOOL)shouldRunOnMainThread {
/* Tell GHUnit to run on a separate thread */
return YES;
}
答案 1 :(得分:-1)
你无法在单元测试中做任何视觉效果。视图永远不会被实际加载。此外,您不需要测试awakeAfterUsingCoder
被调用。这就是Apple的东西。通常,您的单元测试必须只测试您的逻辑。您可以放心地假设从init调用awakeAfterUsingCoder
,因为它是Apple的代码。您只需要确保调用您的方法