在Xcode UItesting的testing案例中延迟/等待

我正在尝试使用Xcode 7 beta 2中提供的新UItesting编写一个testing用例。该应用程序有一个login屏幕,用于呼叫服务器进行login。 这是一个延迟,因为这是一个asynchronous操作。

在继续执行下一步之前,是否有办法在XCTestCase中引起延迟或等待机制?

没有适当的文档可用,我经历了类的头文件。 无法find与此相关的任何内容。

任何想法/build议?

在Xcode 7 Beta 4中引入了asynchronousUItesting。要等待文本为“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) 

有关UItesting的更多细节可以在我的博客上find。

另外,你可以睡觉:

 sleep(10) 

由于UITests在另一个进程中运行,所以这个工作。 我不知道这是多么可取,但是有效。

Xcode 9引入了XCTWaiter的新技巧

testing用例明确地等待

 wait(for: [documentExpectation], timeout: 10) 

服务员实例委托testing

 XCTWaiter(delegate: self).wait(for: [documentExpectation], timeout: 10) 

服务员类返回结果

 let result = XCTWaiter.wait(for: [documentExpectation], timeout: 10) if result == .timedOut { //handle timeout } 

================================================== ==========

在Xcode 9之前

目标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]; } }]; } 

用法

 XCUIElement *element = app.staticTexts["Name of your element"]; [self waitForElementToAppear:element withTimeout:5]; 

迅速

 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) } } } 

用法

 let element = app.staticTexts["Name of your element"] self.waitForElementToAppear(element) 

要么

 let element = app.staticTexts["Name of your element"] self.waitForElementToAppear(element, timeout: 10) 

资源

从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 } 

另一个诀窍是写一个waitfunction,信贷去约翰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中,UItesting现在有expectationForPredicate:evaluatedWithObject:handler:

原版的:

另一种方法是旋转运行循环一段时间。 真的只有在知道需要等待多less(估计)时间时才有用

Obj-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>>))

如果您需要testing一些条件以继续testing,这并不是非常有用。 要运行条件检查,请使用while循环。

iOS 11 / Xcode 9引入了<yourElement>.waitForExistence(timeout: 5) 。 这是本网站所有自定义实现的绝佳替代品!

根据@ 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) } } } } 

你可以像这样使用它

 let element = app.staticTexts["Name of your element"] waitFor(object: element) { $0.exists } 

它也允许等待一个元素消失,或任何其他属性改变(通过使用适当的块)

 waitFor(object: element) { !$0.exists } // Wait for it to disappear 

以下代码只适用于Objective C

 - (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]; } 

只要打电话给这个function,如下所示。

 [self wait: 10]; 

根据XCUIElement的API,存在可用于检查查询是否存在,因此在某些情况下,以下语法可能会有用!

 let app = XCUIApplication() app.launch() let label = app.staticTexts["Hello, world!"] while !label.exists { sleep(1) } 

如果你确信你的期望将会得到满足,那么你可以尝试运行这个。 应该注意的是,如果wait等待时间太长,应该使用来自@Joe Masilotti的post的waitForExpectationsWithTimeout(_,handler:_)