我正在尝试在iOS项目中设置一个简单的OCMock单元测试,只是为了熟悉框架。
我有一个模拟的DataLoader
类,即使我自己调用这个方法,我的期望也会失败:
- (void)testSimpleMocking {
// Mock the class
id mock = [OCMockObject niceMockForClass:[DataLoader class]];
// Override the 'dispatchLoadToAppDelegate:' to be a no-op
[[[mock stub] andReturn:nil] dispatchLoadToAppDelegate:[OCMArg any]];
// Expect the method to be called
[[mock expect] dispatchLoadToAppDelegate:[OCMArg any]];
// Call the method
[mock dispatchLoadToAppDelegate:nil];
// Verify
[mock verify];
}
但是,当我运行此测试时,收到错误:
/Users/Craig/projects/MyApp/Unknown.m: -[MockingDataLoaderTest testSimpleMocking] : OCMockObject[DataLoader]:
expected method was not invoked: dispatchLoadToAppDelegate:<OCMAnyConstraint: 0x1a3d890>
当我自己调用这个方法时,这怎么可能?
编辑:更复杂的案例:
- (void)testDataLoaderWaitsForDownload {
id mock = [OCMockObject niceMockForClass:[DataLoader class]];
id metadataItem = [OCMockObject niceMockForClass:[NSMetadataItem class]];
// Prepare NSMetadataItem
[[[metadataItem expect] andReturn:nil] valueForAttribute:NSMetadataItemURLKey];
// CODERUN
[mock waitForDownload:metadataItem thenLoad:YES];
//VERIFY
[metadataItem verify];
}
waitForDownload:thenLoad:
方法的实现:
- (void)waitForDownload:(NSMetadataItem *)file thenLoad:(BOOL)load {
NSURL *metadataItemURL = [file valueForAttribute:NSMetadataItemURLKey];
...
因错误而失败:
Unknown.m:0: error: -[MockingDataLoaderTest testDataLoaderWaitsForDownload] : OCMockObject[NSMetadataItem]: expected method was not invoked: valueForAttribute:@"kMDItemURL"
答案 0 :(得分:6)
在您的测试中,stub
优先考虑,因为它首先被调用。如果您切换expect
和stub
的顺序,您的测试应该通过。
同时使用expect
和stub
(具有相同的参数期望)的原因是确保至少发生一次调用,然后响应后续调用而不失败。
如果你真的只想要一个方法调用,只需将andReturn:
添加到expect子句......
- (void)test_dispatchLoadToAppDelegate_isCalledExactlyOnce {
// Mock the class
id mock = [OCMockObject niceMockForClass:[DataLoader class]];
// Expect the method to be called
[[[mock expect] andReturn:nil] dispatchLoadToAppDelegate:[OCMArg any]];
// Call the method
[mock dispatchLoadToAppDelegate:nil];
// Verify
[mock verify];
}
另一种情况:
- (void)test_dispatchLoadToAppDelegate_isCalledAtLeastOnce {
// Mock the class
id mock = [OCMockObject niceMockForClass:[DataLoader class]];
// Expect the method to be called
[[[mock expect] andReturn:nil] dispatchLoadToAppDelegate:[OCMArg any]];
// Handle subsequent calls
[[[mock stub] andReturn:nil] dispatchLoadToAppDelegate:[OCMArg any]];
// Call the method
[mock dispatchLoadToAppDelegate:nil];
// Call the method (again for fun!)
[mock dispatchLoadToAppDelegate:nil];
// Verify
[mock verify];
}
对于这种特殊情况,看起来你可以使用niceMockForClass
,但如果你想要存根返回非零,那么你必须以任何一种方式调用stub
。
答案 1 :(得分:3)
Ben Flynn是正确的,扭转stub
和expect
的顺序应该会让你的测试通过,但我会更进一步,建议你删除stub
来电。您编写此测试的方式表明stub
是expect
的先决条件,而不是expect
。
stub
表示该方法必须只调用一次(对于每个期望)。 expect
表示该方法可以被调用零次或多次。通常,您stub
调用对测试很重要,{{1}}会产生副作用。或者使用一个漂亮的模拟,只为重要的调用设置期望。