在UITableViewCell XCTest中测试单元

时间:2019-05-23 06:42:29

标签: ios swift tdd xctest

我正在测试视图控制器所在的UITableView

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    func setup() {
        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
    }


    var data = [1,2,3,4,5,6,7]
}

extension ViewController : UITableViewDelegate {

}

extension ViewController : UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row].description
        return cell
    }    
}

通过测试

func testViewCell() {
    guard let controller = controller else {
        return XCTFail("Could not instantiate ViewController")
    }

    let tableCell = Bundle(for: CustomTableViewCell.self).loadNibNamed("CustomTableViewCell", owner: nil)?.first as! CustomTableViewCell
    tableCell.textLabel?.text = "2"

    controller.loadViewIfNeeded()
    let actualCell = controller.tableView!.cellForRow(at: IndexPath(row: 0, section: 0) )

    XCTAssertEqual(actualCell, tableCell)}

但是我得到的单元格为零。

这是令人惊讶的,因为视图控制器中的断点指示正在分配单元格,因此该行出现了问题

let actualCell = controller.tableView!.cellForRow(at: IndexPath(row: 0, section: 0) )

那我该如何测试该单元格的内容?

2 个答案:

答案 0 :(得分:0)

问题1: 如果您在笔尖中定义单元格,则需要注册该笔尖(而不是类型)。

tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")

问题2: 似乎直接调用controller.tableView!.cellForRow(at:)可以返回nil。但这不是UIKit调用表视图的方式。而是通过其数据源调用它。让我们的测试做同样的事情:

let actualCell = controller.tableView.dataSource?.tableView(controller.tableView, cellForRowAt: IndexPath(row: 0, section: 0))

现在返回一个单元格,并且断言失败,表明CustomTableViewCell的两个实例不相等。

奖金:如果您想将数据源移到一个单独的类中,则可以这样做而无需更改测试。该测试不知道或不在乎谁实现数据源。

问题3: 更改测试以将"1"设置为期望单元格的文本标签仍然没有通过。这可能是因为每个单元格都有自己的layer。因此,与其设置期望的单元格,不如将实际的单元格强制转换为CustomTableViewCell。然后,您可以检查其属性。

guard let cell = actualCell as? CustomTableViewCell else {
     XCTFail("Expected \(CustomTableViewCell.self), but was \(actualCell)")
     return
}
XCTAssertEqual(cell.textLabel?.text, "1")

改进: 遍历表视图的数据源,并将表视图作为第一个参数传递给它很尴尬。通过定义独立的辅助函数,我们可以使读写表视图测试变得更加容易。

func cellForRow(in tableView: UITableView, row: Int, section: Int = 0) -> UITableViewCell? {
    return tableView.dataSource?.tableView(tableView, cellForRowAt: IndexPath(row: row, section: section))
}

使用此帮助程序,我们可以简单地编写:

let actualCell = cellForRow(in: controller.tableView row: 0)

我的书 {iOS Unit Testing by Example: XCTest Tips and Techniques Using Swift

中描述了遍历数据源的需求(以及简化它的辅助函数)。

答案 1 :(得分:0)

步骤1:在情节提要中转到视图控制器的Identity Inspector,并为其指定一个情节提要ID。例如:“ vcIdentifier”

第2步:您已经在单元测试中获得了情节提要的实例

第3步:通过第2步中的情节提要实例实例化视图控制器

第4步:从viewcontroller中访问表视图,并将其传递给测试中的'cellForRowAt'方法。请参见下面的示例代码:

let storyboard = UIStoryboard(name: "Main", bundle:nil)
let newsViewController: UITableViewController = storyboard.instantiateViewController(identifier: "vcIdentifier")
return newsViewController.tableView // Use this tableview to call 'cellforRow'

第5步:删除测试代码中添加的所有tableview.register()方法。如果您注册单元格方法,所有的网点都会丢失。