15

我正在试验(Xcode 7)UI XCTestCase 测试用例,我偶然发现了一个 UIView 的问题,其中我有一个包含许多单元格(4000+)的 UITableView。

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

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

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

有解决方法吗?是否有可能跳过构建 UI 树层次结构的一部分或其他什么?我的目标是能够为此屏幕编写 UI 测试。

4

2 回答 2

5

firstMatch如果您可以使用而不是,您也许可以避免渲染整个表格element,并且还可以避免count

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

我调整了我的测试,使其不太精确,但对我来说仍然足够好(考虑到否则会花费大量时间)。相反,我使用matchingwith 对预期标签值的谓词 withfirstMatch来查找与我想要的条件匹配的第一个单元格。这样,一旦找到它们,遍历就会停止(并且由于它们位于表的顶部,因此很快)。

这是之前和之后的代码。

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

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 属性访问查询的结果。element 属性在返回之前遍历您应用的可访问性树以检查多个匹配元素,如果没有单个匹配元素,则当前测试失败。

如果您明确知道会有一个匹配元素,请改用 XCUIElementTypeQueryProvider firstMatch 属性。firstMatch 在找到匹配元素后立即停止遍历应用的可访问性层次结构,从而加快元素查询解析。

于 2018-10-31T23:16:34.080 回答
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()
于 2016-02-08T21:35:43.910 回答