unit test custom UITableViewCell?

Viewed 4633

Is it possible to init and load only custom cell and test outlets?

My ViewController has TableView with separated dataSource ( which is subclass of custom data source ). So it's kinda tricky to create cell using all of those.

Custom cell has only a couple of labels and config method for updating them from object, so if loaded, testing would be easy.

2 Answers

It is possible to write a unit test for custom UITableViewCell that will test its outlets and any other functionality included in it. The following sample demonstrates this:

class TestItemTableViewCell: XCTestCase {

var tableView: UITableView!
private var dataSource: TableViewDataSource!
private var delegate: TableViewDelegate!

override func setUp() {
    tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 200, height: 400), style: .plain)
    let itemXib = UINib.init(nibName: "ItemTableViewCell",
                                    bundle: nil)
    tableView.register(itemXib,
                       forCellReuseIdentifier: "itemCell")
    dataSource = TableViewDataSource()
    delegate = TableViewDelegate()
    tableView.delegate = delegate
    tableView.dataSource = dataSource
}

func testAwakeFromNib() {
    let indexPath = IndexPath(row: 0, section: 0)
    let itemCell = createCell(indexPath: indexPath)

    // Write assertions for things you expect to happen in
    // awakeFromNib() method.
}

}


extension TestItemTableViewCell {

func createCell(indexPath: IndexPath) -> ItemTableViewCell {
    
    let cell = dataSource.tableView(tableView, cellForRowAt: indexPath) as! ItemTableViewCell
    XCTAssertNotNil(cell)
    
    let view = cell.contentView
    XCTAssertNotNil(view)
    
    return cell
}
}

private class TableViewDataSource: NSObject, UITableViewDataSource {

var items = [Item]()

override init() {
    super.init()
    
    // Initialize model, i.e. create&add object in items.
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return items.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell",
                                             for: indexPath)
    return cell
}
}

private class TableViewDelegate: NSObject, UITableViewDelegate {

 }

This approach mimics the way UITableViewCells are created/reused at runtime. The same methods get called, e.g. awakeFromNib, IBOutlets initialized, etc. I am sure you can even test the sizing of the cell (e.g. height) even though I haven't tried that yet. Note that having a view model where the "visualization" logic of your model object is contained is a good & modular approach and makes it easier to unit test parts of the code (as described in another answer above). However, with a unit test for a view model object, you cannot test the entire lifecycle of a UITableViewCell.

Related