ios Xcode UI 测试用例中的延迟/等待
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31182637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Delay/Wait in a test case of Xcode UI testing
提问by Tejas HS
I am trying to write a test case using the new UI Testing available in Xcode 7 beta 2. The App has a login screen where it makes a call to the server to login. There is a delay associated with this as it is an asynchronous operation.
我正在尝试使用 Xcode 7 beta 2 中提供的新 UI 测试编写测试用例。该应用程序有一个登录屏幕,它可以调用服务器进行登录。由于它是异步操作,因此存在与此相关的延迟。
Is there a way to cause a delay or wait mechanism in the XCTestCase before proceeding to further steps?
在继续下一步之前,有没有办法在 XCTestCase 中引起延迟或等待机制?
There is no proper documentation available and I went through the Header files of the classes. Was not able to find anything related to this.
没有适当的文档可用,我浏览了类的头文件。无法找到与此相关的任何内容。
Any ideas/suggestions?
任何想法/建议?
采纳答案by Joe Masilotti
Asynchronous UI Testing was introduced in Xcode 7 Beta 4. To wait for a label with the text "Hello, world!" to appear you can do the following:
异步 UI 测试是在 Xcode 7 Beta 4 中引入的。等待带有文本“Hello, world!”的标签。要出现,您可以执行以下操作:
let app = XCUIApplication()
app.launch()
let label = app.staticTexts["Hello, world!"]
let exists = NSPredicate(format: "exists == 1")
expectationForPredicate(exists, evaluatedWithObject: label, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
More details about UI Testingcan be found on my blog.
更多关于 UI 测试的细节可以在我的博客上找到。
回答by mxcl
Additionally, you can just sleep:
此外,您可以睡觉:
sleep(10)
Since the UITests run in another process, this works. I don't know how advisable it is, but it works.
因为 UITests 在另一个进程中运行,所以这是有效的。我不知道它有多可取,但它有效。
回答by Ted
Xcode 9introduced new tricks with XCTWaiter
Xcode 9引入了XCTWaiter 的新技巧
Test case waits explicitly
测试用例显式等待
wait(for: [documentExpectation], timeout: 10)
Waiter instance delegates to test
Waiter 实例委托进行测试
XCTWaiter(delegate: self).wait(for: [documentExpectation], timeout: 10)
Waiter class returns result
服务员类返回结果
let result = XCTWaiter.wait(for: [documentExpectation], timeout: 10)
switch(result) {
case .completed:
//all expectations were fulfilled before timeout!
case .timedOut:
//timed out before all of its expectations were fulfilled
case .incorrectOrder:
//expectations were not fulfilled in the required order
case .invertedFulfillment:
//an inverted expectation was fulfilled
case .interrupted:
//waiter was interrupted before completed or timedOut
}
sample usage
示例用法
Before Xcode 9
在 Xcode 9 之前
Objective C
目标 C
- (void)waitForElementToAppear:(XCUIElement *)element withTimeout:(NSTimeInterval)timeout
{
NSUInteger line = __LINE__;
NSString *file = [NSString stringWithUTF8String:__FILE__];
NSPredicate *existsPredicate = [NSPredicate predicateWithFormat:@"exists == true"];
[self expectationForPredicate:existsPredicate evaluatedWithObject:element handler:nil];
[self waitForExpectationsWithTimeout:timeout handler:^(NSError * _Nullable error) {
if (error != nil) {
NSString *message = [NSString stringWithFormat:@"Failed to find %@ after %f seconds",element,timeout];
[self recordFailureWithDescription:message inFile:file atLine:line expected:YES];
}
}];
}
USAGE
用法
XCUIElement *element = app.staticTexts["Name of your element"];
[self waitForElementToAppear:element withTimeout:5];
Swift
迅速
func waitForElementToAppear(element: XCUIElement, timeout: NSTimeInterval = 5, file: String = #file, line: UInt = #line) {
let existsPredicate = NSPredicate(format: "exists == true")
expectationForPredicate(existsPredicate,
evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(timeout) { (error) -> Void in
if (error != nil) {
let message = "Failed to find \(element) after \(timeout) seconds."
self.recordFailureWithDescription(message, inFile: file, atLine: line, expected: true)
}
}
}
USAGE
用法
let element = app.staticTexts["Name of your element"]
self.waitForElementToAppear(element)
or
或者
let element = app.staticTexts["Name of your element"]
self.waitForElementToAppear(element, timeout: 10)
回答by blackjacx
iOS 11 / Xcode 9
iOS 11 / Xcode 9
<#yourElement#>.waitForExistence(timeout: 5)
This is a great replacement for all the custom implementations on this site!
这是本网站上所有自定义实现的绝佳替代品!
Be sure to have a look at my answer here: https://stackoverflow.com/a/48937714/971329. There I describe an alternative to waiting for requests which will greatly reduce the time your tests are running!
请务必在此处查看我的回答:https: //stackoverflow.com/a/48937714/971329。我在那里描述了等待请求的替代方法,这将大大减少您的测试运行时间!
回答by onmyway133
As of Xcode 8.3, we can use XCTWaiter
http://masilotti.com/xctest-waiting/
从 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
}
Another trick is to write a wait
function, credit goes to John Sundell for showing it to me
另一个技巧是编写一个wait
函数,感谢 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)
}
}
and use it like
并像使用它一样
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)
}
回答by Ben Lings
Based on @Ted's answer, I've used this extension:
根据@Ted 的回答,我使用了这个扩展:
extension XCTestCase {
// Based on https://stackoverflow.com/a/33855219
func waitFor<T>(object: T, timeout: TimeInterval = 5, file: String = #file, line: UInt = #line, expectationPredicate: @escaping (T) -> Bool) {
let predicate = NSPredicate { obj, _ in
expectationPredicate(obj as! T)
}
expectation(for: predicate, evaluatedWith: object, handler: nil)
waitForExpectations(timeout: timeout) { error in
if (error != nil) {
let message = "Failed to fulful expectation block for \(object) after \(timeout) seconds."
self.recordFailure(withDescription: message, inFile: file, atLine: line, expected: true)
}
}
}
}
You can use it like this
你可以像这样使用它
let element = app.staticTexts["Name of your element"]
waitFor(object: element) { waitFor(object: element) { !- (void)wait:(NSUInteger)interval {
XCTestExpectation *expectation = [self expectationWithDescription:@"wait"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:interval handler:nil];
}
.exists } // Wait for it to disappear
.exists }
It also allows for waiting for an element to disappear, or any other property to change (by using the appropriate block)
它还允许等待元素消失或任何其他属性更改(通过使用适当的块)
[self wait: 10];
回答by enmiller
Edit:
编辑:
It actually just occurred to me that in Xcode 7b4, UI testing now has
expectationForPredicate:evaluatedWithObject:handler:
实际上我突然想到在 Xcode 7b4 中,UI 测试现在有
expectationForPredicate:evaluatedWithObject:handler:
Original:
原来的:
Another way is to spin the run loop for a set amount of time. Really only useful if you know how much (estimated) time you'll need to wait for
另一种方法是将运行循环旋转一段时间。只有当您知道需要等待多少(估计)时间时才真正有用
Obj-C:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: <<time to wait in seconds>>]]
对象-C:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: <<time to wait in seconds>>]]
Swift:
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: <<time to wait in seconds>>))
迅速:
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: <<time to wait in seconds>>))
This is not super useful if you need to test some conditions in order to continue your test. To run conditional checks, use a while
loop.
如果您需要测试某些条件以继续测试,这不是很有用。要运行条件检查,请使用while
循环。
回答by arango_86
The following code just works with Objective C.
以下代码仅适用于 Objective C。
let _ = XCTWaiter.wait(for: [XCTestExpectation(description: "Hello World!")], timeout: 2.0)
Just make call to this function as given below.
只需调用此函数,如下所示。
let app = XCUIApplication()
app.launch()
if let label = app.staticTexts["Hello, world!"] {
label.waitForExistence(timeout: 5)
}
回答by yoAlex5
In my case sleep
created side effect so I used wait
在我的情况下sleep
产生了副作用,所以我使用了wait
回答by zdravko zdravkin
sleep will block the thread
sleep 会阻塞线程
"No run loop processing occurs while the thread is blocked."
“当线程被阻塞时,不会发生运行循环处理。”
you can use waitForExistence
你可以使用 waitForExistence
##代码##