Xcode UI 테스트의 경우 지연/대기
저는 Xcode 7 베타 2에서 사용할 수 있는 새로운 UI 테스트를 사용하여 테스트 케이스를 작성하려고 합니다.앱에는 로그인을 위해 서버에 전화를 거는 로그인 화면이 있습니다.비동기 작업이므로 이와 관련된 지연이 있습니다.
추가 단계로 진행하기 전에 XCT 테스트 케이스에서 지연 또는 대기 메커니즘을 발생시킬 수 있는 방법이 있습니까?
사용할 수 있는 적절한 문서가 없고 수업의 헤더 파일을 검토했습니다.이것과 관련된 어떤 것도 찾을 수 없었습니다.
아이디어/제안이 있습니까?
또한 잠만 자도 됩니다.
sleep(10)
UIT 테스트는 다른 프로세스에서 실행되므로 이 작업이 가능합니다.그게 얼마나 바람직한지는 모르겠지만, 효과가 있어요.
비동기 UI 테스트는 Xcode 7 베타 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)
UI 테스트에 대한 자세한 내용은 블로그에서 확인할 수 있습니다.
iOS 11 / Xcode 9
<#yourElement#>.waitForExistence(timeout: 5)
이 사이트의 모든 사용자 지정 구현을 대체할 수 있는 훌륭한 솔루션입니다!
여기 제 대답을 꼭 보세요: https://stackoverflow.com/a/48937714/971329 .여기에서는 테스트 실행 시간을 크게 단축할 수 있는 요청을 기다리는 것에 대한 대안을 설명합니다.
Xcode 9는 XCTWaiter로 새로운 트릭을 도입했습니다.
테스트 사례가 명시적으로 대기합니다.
wait(for: [documentExpectation], timeout: 10)
테스트할 웨이터 인스턴스 딜러
XCTWaiter(delegate: self).wait(for: [documentExpectation], timeout: 10)
웨이터 클래스 결과 반환
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
}
견본 용법
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
}
또 다른 속임수는 다음과 같습니다.wait
기능, 나에게 그것을 보여준 존 선델에게 공이 갑니다.
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)
}
이렇게 하면 스레드를 절전 모드로 전환하거나 시간 초과 시 오류를 발생시키지 않고 지연이 발생합니다.
let delayExpectation = XCTestExpectation()
delayExpectation.isInverted = true
wait(for: [delayExpectation], 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."
let location = XCTSourceCodeLocation(filePath: file, lineNumber: line)
let issue = XCTIssue(type: .assertionFailure, compactDescription: message, detailedDescription: nil, sourceCodeContext: .init(location: location), associatedError: nil, attachments: [])
self.record(issue)
}
}
}
}
이렇게 사용하시면 됩니다.
let element = app.staticTexts["Name of your element"]
waitFor(object: element) { $0.exists }
또한 요소가 사라지거나 다른 속성이 변경될 때까지 기다릴 수 있습니다(해당 블록 사용).
waitFor(object: element) { !$0.exists } // Wait for it to disappear
Xcode 테스트 대기
내 경우에는sleep
부작용을 만들어서 사용했습니다.wait
let _ = XCTWaiter.wait(for: [XCTestExpectation(description: "Hello World!")], timeout: 2.0)
편집:
사실 방금 Xcode 7b4에서 UI 테스트가 이제expectationForPredicate:evaluatedWithObject:handler:
원본:
다른 방법은 설정된 시간 동안 실행 루프를 회전하는 것입니다.대기 시간(추정)을 알고 있는 경우에만 유용합니다.
Obj-C:[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: <<time to wait in seconds>>]]
스위프트:NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: <<time to wait in seconds>>))
테스트를 계속하기 위해 일부 조건을 테스트해야 하는 경우에는 이 방법이 그다지 유용하지 않습니다.조건부 검사를 실행하려면 다음을 사용합니다.while
루우프
현재 회사에서는 XCUIelement 표현식 기대치를 생성하여 다양한 방법으로 대기하고 있습니다.유지관리가 가능한지 확인하기 위해 다음과 같은 방법으로 작업을 수행합니다(기대되는 다양성이 많으므로 이를 위해 많은 메소드/특정 술어를 생성하고 싶지 않습니다).
스위프트 5
기저법
표현식은 동적 술어 값을 형성하는 데 사용됩니다.우리는 만들 수 있습니다.XCTNSPredicateExpectation
'는 술어에서 나온 것이고, 우리는 그 다음에 그것을 전달합니다.XCTWaiter
명시적으로 기다리는 것.그 결과가 다른 것이었다면completed
선택적인 메시지로 실패합니다.
@discardableResult
func wait(
until expression: @escaping (XCUIElement) -> Bool,
timeout: TimeInterval = 15,
message: @autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) -> Self {
if expression(self) {
return self
}
let predicate = NSPredicate { _, _ in
expression(self)
}
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: nil)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
if result != .completed {
XCTFail(
message().isEmpty ? "expectation not matched after waiting" : message(),
file: file,
line: line
)
}
return self
}
사용.
app.buttons["my_button"].wait(until: { $0.exists })
app.buttons["my_button"].wait(until: { $0.isHittable })
키 경로
다음 및 keyPath가 keyPath인 .match
식의 값입니다.
@discardableResult
func wait<Value: Equatable>(
until keyPath: KeyPath<XCUIElement, Value>,
matches match: Value,
timeout: TimeInterval = 15,
message: @autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) -> Self {
wait(
until: { $0[keyPath: keyPath] == match },
timeout: timeout,
message: message,
file: file,
line: line
)
}
사용.
app.buttons["my_button"].wait(until: \.exists, matches: true)
app.buttons["my_button"].wait(until: \.isHittable, matches: false)
그런 다음 당신은 그 방법을 포장할 수 있습니다, 어디에서.match
은 항상 값은항입니다.true
가장 일반적인 사용 사례입니다.
사용.
app.buttons["my_button"].wait(until: \.exists)
app.buttons["my_button"].wait(until: \.isHittable)
저는 그것에 대해 게시물을 썼고, 거기서도 전체 확장 파일을 얻습니다: https://sourcediving.com/clean-waiting-in-xcuitest-43bab495230f
다음 코드는 목표 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];
}
아래와 같이 이 기능으로 전화를 걸면 됩니다.
[self wait: 10];
잠은 실을 막을 것입니다.
"스레드가 차단된 동안에는 실행 루프 처리가 발생하지 않습니다."
waitForExist를 사용할 수 있습니다.
let app = XCUIApplication()
app.launch()
if let label = app.staticTexts["Hello, world!"] {
label.waitForExistence(timeout: 5)
}
let app = XCUIApplication()
app.launch()
//Find the button in the UI
let SettingsButton =
app.navigationBars["HomeView"].buttons["Settings"]
XCTAssertTrue(settingButton.waitForExistence(timeout: 10))
XCUIelement 에 .exists
쿼리가 존재하는지 여부를 확인하는 데 사용할 수 있으므로 다음 구문이 경우에 따라 유용할 수 있습니다!
let app = XCUIApplication()
app.launch()
let label = app.staticTexts["Hello, world!"]
while !label.exists {
sleep(1)
}
최종적으로 기대가 충족될 것으로 확신하는 경우 이를 실행해 볼 수 있습니다.하는 것이 더 수 .waitForExpectationsWithTimeout(_,handler:_)
@Joe Masilotti의 게시물에서 사용해야 합니다.
언급URL : https://stackoverflow.com/questions/31182637/delay-wait-in-a-test-case-of-xcode-ui-testing
'programing' 카테고리의 다른 글
Excel이 내 CSV의 URL을 하이퍼링크로 해석할 수 있습니까? (0) | 2023.05.07 |
---|---|
포스트 데이터로 리디렉션하는 방법(장고) (0) | 2023.05.07 |
VB.NET: 데이터 그리드 보기 지우기 (0) | 2023.05.07 |
단일 SELECT 문에 공통 테이블 식을 여러 개 사용하려면 어떻게 해야 합니까? (0) | 2023.05.07 |
git stash pop과 git stash 적용 간의 차이 (0) | 2023.05.07 |