2

我正在尝试为实现NSFetchedResultsControllerDelegate 协议的视图控制器编写单元测试。实现的第一个测试(在此视图控制器的一些其他测试之后)是验证在插入新对象时是否将表行插入到表视图中。

我的第一个测试实现是:

- (void) setUp {
    [super setUp];

    sut = [[JODataTableViewController alloc] init];
    fetchedResultsCtrlrMock = [OCMockObject niceMockForClass:[NSFetchedResultsController class]];
    NSError *__autoreleasing *err = (NSError *__autoreleasing *) [OCMArg anyPointer];
    [[[fetchedResultsCtrlrMock expect] andReturnValue:OCMOCK_VALUE((BOOL){YES})] performFetch:err];
    [sut setValue:fetchedResultsCtrlrMock forKey:@"fetchedResultsController"];
    [sut view]; // This invokes viewDidLoad.
}

- (void) tearDown {
    sut = nil;

    [super tearDown];
}

- (void) testObjectInsertedInResultsAddsARowToTheTable {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    id tableViewMock = [OCMockObject mockForClass:[UITableView class]];
    sut.tableView = tableViewMock;
    [[tableViewMock expect] insertRowsAtIndexPaths:@[indexPath]
                                  withRowAnimation:UITableViewRowAnimationLeft];

    [sut controller:nil didChangeObject:nil
        atIndexPath:nil
      forChangeType:NSFetchedResultsChangeInsert
       newIndexPath:indexPath];

    [tableViewMock verify];
}

当它试图在视图控制器中实现功能以移动到绿色状态(TDD)时,我编写了以下代码:

- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (void) controller:(NSFetchedResultsController *)controller
    didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
      forChangeType:(NSFetchedResultsChangeType)type
       newIndexPath:(NSIndexPath *)newIndexPath {
    UITableViewCell *cell;

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath]
                                  withRowAnimation:UITableViewRowAnimationLeft];
            break;

    }
}


- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

但是,我无法让它通过,错误是:

Test Case '-[JODataTableViewControllerTests testObjectInsertedInResultsAddsARowToTheTable]' started.
Unknown.m:0: error: -[JODataTableViewControllerTests testObjectInsertedInResultsAddsARowToTheTable] : OCMockObject[UITableView]: unexpected method invoked: isKindOfClass:<??> 
Test Case '-[JODataTableViewControllerTests testObjectInsertedInResultsAddsARowToTheTable]' failed (0.001 seconds).

我尝试在测试的准备部分添加一次或多次以下行,结果相同。

[[[tableViewMock expect] andReturnValue:OCMOCK_VALUE((BOOL){YES})] isKindOfClass:[OCMArg any]];

如您所见,我目前正在使用OCUnitand OCMock。仅当无法使用此工具集创建此类测试时,我才会考虑其他工具,在这种情况下,如果存在它们的局限性,我将不胜感激。

据我了解,即使被告知,模拟也无法对其班级的性质“撒谎”。此外,该错误未提供有关UITableView正在查找的类的信息。我知道使用 进行测试不是一个好习惯-isKindOfClass:,但这不是我的代码。

感谢您的帮助。

4

2 回答 2

0

我以前见过与isKindOfClass:调用相关的失败,它们通常是 Apple 在自己的代码中实现某个功能的结果。该标准mockForClass:将拒绝任何意外消息作为失败情况。一个简单的解决方案是将您的模拟切换到niceMockForClass:可以容忍此类意外消息的模拟。

添加对来自第三方代码的消息的期望将使您的测试与外部实现细节非常耦合。确保isKindOfClass:被调用显然不是您系统的明确要求。

于 2013-04-22T03:12:31.987 回答
0

解决模拟隐藏了内部行为的对象的一种方法是使用部分模拟。在你的情况下:

id tableViewMock = [OCMock partialMockForObject:[[UITableView alloc] init]];

当我这样做时,我通常会稍微更改名称并调用它tableViewPartial

于 2013-04-24T17:38:14.770 回答