繁体   English   中英

如何对NSFetchedResultsControllerDelegate进行单元测试?

[英]How to unit test NSFetchedResultsControllerDelegate?

我正在尝试为实现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]];

如您所见,我目前正在使用OCUnitOCMock 仅当无法使用此工具集创建此类测试时,我才会考虑使用其他工具,在这种情况下,如果它们存在,我希望对它们的局限性做出解释。

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

谢谢您的帮助。

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

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

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

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

当我这样做时,我通常会稍微更改名称,并将其命名为tableViewPartial

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM