我正在尝试使用Xcode 7 beta 2中提供的新UI测试编写一个测试用例。该应用程序有一个登录屏幕,它调用服务器登录。由于这是一个异步操作,因此存在与此相关的延迟。
在进行进一步的步骤之前,是否有一种方法可以在XCTestCase中引起延迟或等待机制?
没有合适的文档,我浏览了类的头文件。找不到任何与此相关的信息。
意见/建议吗?
我正在尝试使用Xcode 7 beta 2中提供的新UI测试编写一个测试用例。该应用程序有一个登录屏幕,它调用服务器登录。由于这是一个异步操作,因此存在与此相关的延迟。
在进行进一步的步骤之前,是否有一种方法可以在XCTestCase中引起延迟或等待机制?
没有合适的文档,我浏览了类的头文件。找不到任何与此相关的信息。
意见/建议吗?
当前回答
从Xcode 8.3开始,我们可以使用XCTWaiter http://masilotti.com/xctest-waiting/
func waitForElementToAppear(_ element: XCUIElement) -> Bool {
let predicate = NSPredicate(format: "exists == true")
let expectation = expectation(for: predicate, evaluatedWith: element,
handler: nil)
let result = XCTWaiter().wait(for: [expectation], timeout: 5)
return result == .completed
}
另一个技巧是写一个等待函数,感谢John Sundell给我演示了它
extension XCTestCase {
func wait(for duration: TimeInterval) {
let waitExpectation = expectation(description: "Waiting")
let when = DispatchTime.now() + duration
DispatchQueue.main.asyncAfter(deadline: when) {
waitExpectation.fulfill()
}
// We use a buffer here to avoid flakiness with Timer on CI
waitForExpectations(timeout: duration + 0.5)
}
}
然后像这样使用它
func testOpenLink() {
let delegate = UIApplication.shared.delegate as! AppDelegate
let route = RouteMock()
UIApplication.shared.open(linkUrl, options: [:], completionHandler: nil)
wait(for: 1)
XCTAssertNotNil(route.location)
}
其他回答
编辑:
我突然想到在Xcode 7b4中,UI测试现在有 expectationForPredicate: evaluatedWithObject:处理程序:
原:
另一种方法是在一段时间内旋转运行循环。只有当你知道你需要等待多长时间时才有用
Obj-C: [NSRunLoop currentRunLoop] runMode: nsdefaultrunopmode befordate:[NSDate datetimeintervalcenow: << <time wait in sec >>]
迅速: NSRunLoop.currentRunLoop().runMode(nsdefuultrunloopmode, beforeDate: NSDate(timeIntervalSinceNow: <<time to wait in seconds>>)))
如果您需要测试某些条件才能继续测试,那么这并不是非常有用。要运行条件检查,请使用while循环。
let app = XCUIApplication()
app.launch()
//Find the button in the UI
let SettingsButton =
app.navigationBars["HomeView"].buttons["Settings"]
XCTAssertTrue(settingButton.waitForExistence(timeout: 10))
根据XCUIElement的API, .exists可以用来检查查询是否存在,所以下面的语法在某些情况下是有用的!
let app = XCUIApplication()
app.launch()
let label = app.staticTexts["Hello, world!"]
while !label.exists {
sleep(1)
}
如果你有信心你的期望最终会得到满足,你可以试着运行这个。应该注意的是,如果等待太长,崩溃可能是可取的,在这种情况下,应该使用@Joe Masilotti的帖子中的waitForExpectationsWithTimeout(_,handler:_)。
睡眠会阻塞线程
线程阻塞时不发生运行循环处理。
你可以使用waitForExistence
let app = XCUIApplication()
app.launch()
if let label = app.staticTexts["Hello, world!"] {
label.waitForExistence(timeout: 5)
}
这将创建一个延迟,而不会使线程进入睡眠状态或在超时时抛出错误:
let delayExpectation = XCTestExpectation()
delayExpectation.isInverted = true
wait(for: [delayExpectation], timeout: 5)
因为期望颠倒了,它会悄悄超时。