问题
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