6

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

2 回答 2

6

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

您将两者expect一起使用stub(具有相同的参数期望)的原因是确保至少发生一个调用,然后响应后续调用而不会失败。

如果您真的只需要一个方法调用,只需将andReturn:加到期望子句...

- (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任何一种方式。

于 2013-06-25T23:23:52.157 回答
2

Ben Flynn 是正确的,颠倒顺序stub并且expect应该使您的测试通过,但我会更进一步,建议您应该删除stub呼叫。您编写此测试的方式表明这stub是 的先决条件expect,但事实并非如此。

expect意味着该方法必须被调用一次且仅一次(对于每个期望)。stub表示该方法可以被调用零次或多次。通常,您expect调用对测试很重要的调用以及stub副作用。或者使用一个漂亮的模拟,只为重要的电话设定期望。

于 2013-06-26T16:22:58.657 回答