Table view's `cellForRow(at:)` is `nil` in Unit Test

微笑、不失礼 提交于 2019-12-23 10:15:45

问题


In Unit Test, I have a simple table view with a bunch of basic cells (cells with just a label). I would like to access the cell using cellForRow(at:), so I can test thing like selecting and deselecting the row programmatically, but this cellForRow query always returns nil.

There is some discussion online that I should be using the data source's tableView(_, cellForRowAt:) instead. This is not my intention. I only want to test the cell's visibility, test selecting and deselecting them. To test for visibility, cellForRow(at:) is the right function to use. Furthermore, the data source's tableView(_, cellForRowAt:) has no safeguard for out-of-range index access, while table view's cellForRow(at:) will gracefully return nil in this case, which I also wanted to test my table view controller on.

However, while I can always get a valid cell from tableViewController.tableView(_:cellForRowAt:), I couldn't understand why I always get nil from tableView.cellForRow(at:). I have verified both the tableView and the tableViewController are not nil in my unit test, and I have also triggered view loading with:

_ = tableViewController.view

in setUp(). I also verified with tableView.indexPathsForVisibleRows, and the result does include the index path I used for cellForRow(at:).

When I queried my cell through LLDB and breakpoints, sometimes my cell would show up properly. Is it possible that I am missing things like asynchronous waiting since loading up cells visually may be done in a different thread? Am I supposed to add expectation waiting of some sort to wait until the cells are fully loaded up before I can access them with cellForRow(at:), even through tableView.indexPathsForVisibleRows already returns the expected index paths.? I tried to set this up but I'm not sure how to override my table view controller's init().

Here's my code in the Unit Test class.

import XCTest
@testable import TableViewTest
class TableViewTestTests: XCTestCase {
   
    private var appDelegate: AppDelegate!
    private var tableVC: TableViewController!
   
    override func setUp() {
        super.setUp()
        
        appDelegate = UIApplication.shared.delegate as! AppDelegate
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)        
        tableVC = storyboard.instantiateViewController(withIdentifier: "TableViewController") as! TableViewController
       
        // Trigger view load and viewDidLoad()
        _ = tableVC.view
       
    }
   
    override func tearDown() {
        
        super.tearDown()
    }
    func testGetFirstRow() {
        let tableView = tableVC.tableView!
        let indexPath0 = IndexPath(item: 0, section: 0)

        let cell0 = tableView.cellForRow(at: indexPath0)
       
        let visibleRows = tableView.indexPathsForVisibleRows
        XCTAssert(visibleRows != nil)   // PASSED
        XCTAssert(tableView.indexPathsForVisibleRows!.contains(indexPath0)) // PASSED
       
        XCTAssert(cell0 != nil)     // FAILED
    }
   
    func testGetFirstRowDataSource() {
        let tableView = tableVC.tableView!
        let indexPath0 = IndexPath(item: 0, section: 0)
       
        // This won't check for cell visibility.
        let cell0 = tableVC.tableView(tableView, cellForRowAt: indexPath0)
       
        let visibleRows = tableView.indexPathsForVisibleRows
        XCTAssert(visibleRows != nil)           // PASSED
        XCTAssert(tableView.indexPathsForVisibleRows!.contains(indexPath0))     // PASSED
    }

来源:https://stackoverflow.com/questions/42466837/table-views-cellforrowat-is-nil-in-unit-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!