简体   繁体   English

在 UITableViewCell XCTest 中测试单元格

[英]Test Cell in a UITableViewCell XCTest

I'm testing a UITableView where the view controller is我正在测试视图控制器所在的 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
    }    
}

with the test与测试

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)}

However I get the cell as nil.但是我得到的单元格为零。

This is surprising since a breakpoint in the view controller indicates that the cell is being allocated, so there is something wrong in the line这是令人惊讶的,因为视图控制器中的断点表明正在分配单元格,因此行中有错误

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

So how can I test the contents of this cell?那么如何测试这个单元格的内容呢?

Problem 1: If you define your cell in a nib, you need to register that nib (instead of the type).问题 1:如果您在笔尖中定义单元格,则需要注册该笔尖(而不是类型)。

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

Problem 2: It seems directly calling controller.tableView!.cellForRow(at:) can return nil .问题二:好像直接调用controller.tableView!.cellForRow(at:)可以返回nil But this isn't how UIKit calls your table view.但这不是 UIKit 调用表格视图的方式。 Instead, call it through its data source.相反,通过其数据源调用它。 Let's have the test do the same:让我们做同样的测试:

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

This now returns a cell, and the assertion fails saying the two instances of CustomTableViewCell aren't equal.现在返回一个单元格,并且断言失败,说明 CustomTableViewCell 的两个实例不相等。

Bonus: If you ever want to move the data source into a separate class, you can do so without changing the test.奖励:如果您想将数据源移动到一个单独的类中,您可以在不更改测试的情况下这样做。 The test doesn't know or care who implements the data source.测试不知道也不关心谁实现了数据源。

Problem 3: Changing the test to set "1" as the text label of the expected cell still doesn't pass.问题 3:更改测试以设置"1"作为预期单元格的文本标签仍然没有通过。 This may be because each cell has its own layer .这可能是因为每个单元格都有自己的layer So instead of setting up an expected cell, cast the actual cell to a CustomTableViewCell.因此,与其设置预期的单元格,不如将实际单元格转换为 CustomTableViewCell。 Then you can inspect its properties.然后你可以检查它的属性。

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

Improvement: Going through the table view's data source, and passing it the table view as the first argument is awkward.改进:遍历表视图的数据源,并将表视图作为第一个参数传递给它很尴尬。 We can make it easier to read and write table view tests by defining standalone helper functions.通过定义独立的辅助函数,我们可以更容易地阅读和编写表格视图测试。

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

Using this helper, we can simply write:使用这个助手,我们可以简单地写:

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

Step 1: Go to Identity Inspector of your view controller in storyboard and give it a storyboard id.第 1 步:转到故事板中视图控制器的 Identity Inspector 并为其指定故事板 ID。 Ex: "vcIdentifier"例如:“vcIdentifier”

Step 2: You have get the instance of your storyboard in Unit test第 2 步:您已经在单元测试中获得了故事板的实例

Step 3 : Instantiate your view controller via storyboard instance from step 2第 3 步:通过第 2 步中的故事板实例实例化您的视图控制器

Step 4 : Get access to your table view from the viewcontroller and pass it to 'cellForRowAt' method in your test.第 4 步:从视图控制器访问您的表视图,并将其传递给测试中的“cellForRowAt”方法。 Please see below a sample code:请参阅下面的示例代码:

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

Step 5: Remove any tableview.register() method added in your test code.第 5 步:删除在测试代码中添加的任何 tableview.register() 方法。 If you register cell method, all the outlets will be lost.如果注册cell方法,所有的outlet都会丢失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM