XCTestCase - iOS UI测试 - 处理包含许多单元格的UITableView

时间:2015-11-04 18:30:53

标签: ios uitableview xctest xcode-ui-testing xctestcase

我正在尝试使用(XCode 7)UI XCTestCase测试用例,我只是偶然发现了一个UIView的问题,其中我有一个带有许多单元格的UITableView(4000 +)。

当应用程序正常运行时,只渲染可见单元格,并且根本没有性能问题。 但是,如果我在录制XCTestCase的上下文中运行应用程序并导航到此屏幕,则模拟器会冻结,显然是因为每个单个单元格都被渲染为好像是可见的。 如果我尝试手动编写导航脚本并运行XCTestCase,则测试用例在导航到此屏幕后立即失败,退出时出现“UI测试失败 - 无法获得刷新快照”,显然是因为所有单元格都在渲染,这样做没有及时完成。

我认为这与测试框架构建显示的屏幕的整个元模型这一事实有关,将4000多个单元格中的每一个添加到视图树层次结构中。

我尝试添加一个期望,希望这会给测试容器足够的时间来完成渲染所有单元格,但这不起作用。

有解决方法吗?是否有可能跳过构建UI树层次结构的某些部分? 我的目标是能够为这个屏幕编写UI测试。

2 个答案:

答案 0 :(得分:3)

如果可以使用firstMatch而不是element,则可以避免呈现整个表格,并且还可以避免使用count

我进行了一项测试,检查表的前两个单元格中是否有期望的标签。最初,我使用app.table.cells.element(boundBy: 0)app.table.cells.element(boundBy: 1)查找第一个和第二个单元格。这导致在我可以访问单元之前呈现整个表格。

我调整了我的测试,使其精度稍差一些,但对我来说仍然足够好(考虑到要花费大量的时间)。相反,我将matching与预期标签值的谓词一起使用,并将firstMatch与谓词一起使用,以查找与所需条件匹配的前几个单元格。这样,遍历一找到就停止(并且由于它们位于表的顶部,因此很快)。

这是之前和之后的代码。

之前(缓慢但更加精确):

private func checkRhymes(query: String, expectedFirstRhyme: String, expectedSecondRhyme: String) {
    let table = app.tables.element
    let cell0 = table.cells.element(boundBy: 0)
    let cell1 = table.cells.element(boundBy: 1)
    let actualRhyme0 = cell0.staticTexts.matching(identifier: "RhymerCellWordLabel").firstMatch.label
    let actualRhyme1 = cell1.staticTexts.matching(identifier: "RhymerCellWordLabel").firstMatch.label

    XCTAssertEqual(expectedFirstRhyme, actualRhyme0, "Expected first rhyme for \(query) to be \(expectedFirstRhyme) but found \(actualRhyme0)")
    XCTAssertEqual(expectedSecondRhyme, actualRhyme1, "Expected first rhyme for \(query) to be \(expectedSecondRhyme) but found \(actualRhyme1)")
}

速度更快,但精度较低(但足够好):

private func checkRhymes(query: String, expectedFirstRhyme: String, expectedSecondRhyme: String) {
    let table = app.tables.firstMatch
    let label0 = table.cells.staticTexts.matching(NSPredicate(format: "label = %@", expectedFirstRhyme)).firstMatch
    let label1 = table.cells.staticTexts.matching(NSPredicate(format: "label = %@", expectedSecondRhyme)).firstMatch

    // We query for the first cells that we find with the expected rhymes,
    // instead of directly accessing the 1st and 2nd cells in the table,
    // for performance issues.
    // So we can't add assertions for the "first" and "second" rhymes.
    // But we can at least add assertions that both rhymes are visible,
    // and the first one is above the second one.
    XCTAssertTrue(label0.frame.minY < label1.frame.minY)
    XCTAssertTrue(label0.isHittable)
    XCTAssertTrue(label1.isHittable)
}

参考: https://developer.apple.com/documentation/xctest/xcuielementquery/1500515-element

  

在您期望获得以下结果时,使用element属性访问查询结果   查询的单个匹配元素,但要检查多个   访问结果之前先进行含糊不清的匹配。元素属性   遍历您应用的辅助功能树以检查是否有多个匹配项   返回之前的元素,如果没有则通过当前测试   一个匹配的元素。

     

如果您断然知道会有一个   匹配元素,请使用XCUIElementTypeQueryProvider firstMatch   属性。 firstMatch停止遍历您的应用程序的可访问性   一旦找到匹配的元素,就加快了层次结构   查询解析。

答案 1 :(得分:1)

我有同样的问题,我同意等待整个表加载是令人沮丧的,但这是我必须使用以下解决方法。

这可能不是你想要的,但它可能对其他人有所帮助:

基本上我连续2次计算表格中的单元格,如果它们不相等则表示表格仍在加载。把它放在一个循环中然后执行,直到两个计数都返回相同的数字,这意味着表完成加载。然后我停止30秒,这样如果这需要超过30秒,测试将失败(这在我的情况下是足够的时间)。如果你的桌子需要的时间比这要多,你可以将这个数字增加到180,持续3分钟等等......

    let startTime = NSDate()
    var duration : TimeInterval
    var cellCount1 : UInt = app.tables.cells.count
    var cellCount2 : UInt = app.tables.cells.count
    while (cellCount1 != cellCount2) {
        cellCount1 = app.tables.cells.count
        cellCount2 = app.tables.cells.count
        duration = NSDate().timeIntervalSince(startTime as Date)
        if (duration > 30) {
            XCTFail("Took too long waiting for cells to load")
        }
    }
    //Now I know the table is finished loading and I can tap on a cell
    app.tables.cells.element(boundBy: 1).tap()