OCMock“预期的方法没有被调用”,即使我自己称之为

时间:2013-06-25 12:40:40

标签: ios cocoa unit-testing mocking ocmock

我正在尝试在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"

2 个答案:

答案 0 :(得分:6)

在您的测试中,stub优先考虑,因为它首先被调用。如果您切换expectstub的顺序,您的测试应该通过。

同时使用expectstub(具有相同的参数期望)的原因是确保至少发生一次调用,然后响应后续调用而不失败。

如果你真的只想要一个方法调用,只需将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是正确的,扭转stubexpect的顺序应该会让你的测试通过,但我会更进一步,建议你删除stub来电。您编写此测试的方式表明stubexpect的先决条件,而不是expect

stub表示该方法必须只调用一次(对于每个期望)。 expect表示该方法可以被调用零次或多次。通常,您stub调用对测试很重要,{{1}}会产生副作用。或者使用一个漂亮的模拟,只为重要的调用设置期望。