我正在尝试使用(XCode 7)UI XCTestCase测试用例,我只是偶然发现了一个UIView的问题,其中我有一个带有许多单元格的UITableView(4000 +)。
当应用程序正常运行时,只渲染可见单元格,并且根本没有性能问题。 但是,如果我在录制XCTestCase的上下文中运行应用程序并导航到此屏幕,则模拟器会冻结,显然是因为每个单个单元格都被渲染为好像是可见的。 如果我尝试手动编写导航脚本并运行XCTestCase,则测试用例在导航到此屏幕后立即失败,退出时出现“UI测试失败 - 无法获得刷新快照”,显然是因为所有单元格都在渲染,这样做没有及时完成。
我认为这与测试框架构建显示的屏幕的整个元模型这一事实有关,将4000多个单元格中的每一个添加到视图树层次结构中。
我尝试添加一个期望,希望这会给测试容器足够的时间来完成渲染所有单元格,但这不起作用。
有解决方法吗?是否有可能跳过构建UI树层次结构的某些部分? 我的目标是能够为这个屏幕编写UI测试。
答案 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()