首页 文章

如何在UIViewController中单元测试UICollectionView

提问于
浏览
6

我想对UIVollection视图中的UICollectionView进行单元测试(例如,我想测试UICollectionView是否具有我希望它在单元测试中具有的单元格数)

我的单元测试基于以下博客(关于如何对视图控制器进行单元测试):http://yetanotherdevelopersblog.blogspot.co.il/2012/03/how-to-test-storyboard-ios-view.html

在单元测试中,我能够在我正在测试的UIViewController中获得指向UICollectionView的指针 . 这是我的测试的setUp方法中的代码:

storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
viewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];
[viewController performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES];
self.collectionView = viewController.collectionView

不幸的是,这个UICollectionView中没有单元格(即 self.collectionView.visibleCells.count 等于0,因此我无法访问单元格并测试数据是我期望的那样),虽然在调试时我可以看到我的应用程序将这些单元格添加到集合视图 .

我究竟做错了什么?有关如何在UIViewController中单元测试UICollectionView的任何提示和技巧?

Edit: 在Roshan的帮助之后,我现在可以缩小我的问题范围了 . 我正在测试一个有UICollectionView的UIViewController . 在我的单元测试中,我想测试CollectionView中的单元格值是我期待它的 . 但是,我的ViewController上没有调用 collectionView:cellForItemAtIndexPath: ,因此当作为单元测试调用时,我的单元格不存在 . 任何的想法?

2 回答

  • 4

    在iOS上实现TTD时,尽量不要依赖系统调用委托和数据源方法 .

    您应该直接从单元测试中调用这些方法 . 这只是为您的测试配置合适的环境的问题 .

    例如,当我为UICollectionView实现TDD时,我创建两个独立的类专门用于实现UICollectionViewDataSource和UICollectionViewDelegate协议创建一个关注点分离,我可以单独测试这些类到视图控制器本身,虽然我仍然需要初始化查看控制器以设置视图层次结构 .

    这是一个例子,当然省略了 Headers 和其他小部分代码 .

    UICollectionViewDataSource example

    @implementation CellContentDataSource
    
    @synthesize someModelObjectReference = __someModelObjectReference;
    
    #pragma mark - UICollectionViewDataSource Protocol implementation
    
    - (NSInteger) collectionView:(UICollectionView *)collectionView
      numberOfItemsInSection:(NSInteger)section
    {
        return __someModelObjectReference ? 
             [[__someModelObjectReference modelObjects] count] : 0;
    }
    
    - (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView
                   cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString * const kCellReuseIdentifer =   @"Cell";
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifer forIndexPath:indexPath];
    
        ModelObject *modelObject = [__someModelObjectReference modelObjects][[indexPath item]];
    
        /* Various setter methods on your cell with the model object */
    
        return cell;
    }
    @end
    

    Unit Test Example

    - (void) testUICollectionViewDataSource
    {
        UIStoryBoard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
        MainViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"MainViewController"];
        [viewController view]; // Loads the view hierarchy
    
        // Using OCMock to mock the returning of the model objects from the model object reference.
        // The helper method referenced builds an array of test objects for the collection view to reference
        id modelObjectMock = [OCMockObject mockForClass:[SomeModelObjectReference class]];
        [[[modelObjectMock stub] andReturn:[self buildModelObjectsForTest]] modelObjects];
    
        CellContentDataSource *dataSource = [CellContentDataSource new];
        dataSource.someModelObjectReference = modelObjectMock;
        viewController.collectionView.dataSource = dataSource;
    
        // Here we call the data source method directly
        UICollectionViewCell *cell = [dataSource collectionView:viewController.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
    
        XCTAssertNotNil(cell, @"Cell should not be nil");
        // Assert your cells contents here based on your test model objects
    }
    
  • 2

    我没有't know exactly where the problem is but Apple'的文档说这关于 loadView

    你永远不应该直接调用这个方法 . 视图控制器在请求视图属性时调用此方法,但当前为nil . 如果手动创建视图,则必须覆盖此方法并使用它来创建视图 . 如果使用Interface Builder创建视图并初始化视图控制器 - 也就是说,使用initWithNibName:bundle:方法初始化视图,直接设置nibName和nibBundle属性,或者在Interface Builder中创建视图和视图控制器 - 那么你不能覆盖这个方法 .

    因此,不要直接调用它,而是调用 [viewController view] 强制加载视图 .

    至于你的问题,检查 viewController.collectionView 是否为0 . 您的插座可能尚未设置 .

相关问题