Задержка / ожидание в тестовом случае тестирования Xcode UI

Я пытаюсь написать тестовый случай, используя новое тестирование пользовательского интерфейса, доступное в Xcode 7 beta 2. Приложение имеет экран входа в систему, где он делает вызов на сервер для входа в систему. С этим связана задержка, поскольку это асинхронная операция.

есть ли способ вызвать механизм задержки или ожидания в XCTestCase перед переходом к дальнейшим шагам?

нет надлежащей документации, и я прошел через заголовочные файлы классов. Не смог найдите что-нибудь связанное с этим.

любые идеи/предложения?

9 ответов


асинхронное тестирование пользовательского интерфейса было введено в 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)

больше подробнее о тестировании UI можно найти в моем блоге.


кроме того, вы можете просто спать:

sleep(10)

поскольку UITests выполняются в другом процессе, это работает. Я не знаю, насколько это целесообразно, но это работает.


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)

источник


iOS 11 / Xcode 9

<#yourElement#>.waitForExistence(timeout: 5)

Это отличная замена для всех пользовательских реализаций на этом сайте!

обязательно посмотрите на мой ответ здесь:https://stackoverflow.com/a/48937714/971329. Там я описываю альтернативу ожиданию запросов, которые значительно сократят время выполнения ваших тестов!


начиная с 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)
}

Edit:

мне просто пришло в голову, что в Xcode 7b4 тестирование пользовательского интерфейса теперь имеет expectationForPredicate:evaluatedWithObject:handler:

Оригинал:

другой способ-вращать цикл выполнения в течение заданного количества времени. Действительно только полезно, если вы знаете, сколько (расчетное) время вам нужно ждать

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

это не очень полезно, если вам нужно проверить некоторые условия, чтобы продолжить ваш тест. Для выполнения условных проверок используйте while петли.


на основе @Теда!--5-->, я использовал это расширение:

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) { .exists }

Он также позволяет ждать, пока элемент исчезнет или любое другое свойство изменится (с помощью соответствующего блока)

waitFor(object: element) { !.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];
}

просто вызовите эту функцию, как указано ниже.

[self wait: 10];

согласно API для XCUIElement .exists можно использовать, чтобы проверить, существует ли запрос или нет, поэтому в некоторых случаях может быть полезен следующий синтаксис!

let app = XCUIApplication()
app.launch()

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

Если вы уверены, что ваши ожидания будут выполнены в конечном итоге, вы можете попробовать запустить это. Следует отметить, что сбой может быть предпочтительнее, если ожидание слишком долго, и в этом случае waitForExpectationsWithTimeout(_,handler:_) из сообщения @Joe Masilotti следует использовать.