ios ios9 xcode-ui-testing xcode7-beta2 xctwaiter

ios - Retraso/Espera en un caso de prueba de Xcode UI testing



ios9 xcode-ui-testing (10)

A partir de Xcode 8.3, podemos usar 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 }

Otro truco es escribir una función de wait , el crédito va a John Sundell por mostrármelo

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

y úsalo como

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

Estoy tratando de escribir un caso de prueba usando la nueva Prueba de IU disponible en Xcode 7 beta 2. La aplicación tiene una pantalla de inicio de sesión donde realiza una llamada al servidor para iniciar sesión. Hay un retraso asociado con esto, ya que es una operación asincrónica.

¿Hay alguna forma de causar un retraso o mecanismo de espera en XCTestCase antes de continuar con los pasos?

No hay documentación adecuada disponible y revisé los archivos de encabezado de las clases. No pude encontrar nada relacionado con esto.

¿Alguna idea / sugerencia?


Además, solo puedes dormir:

sleep(10)

Como los UITests se ejecutan en otro proceso, esto funciona. No sé qué tan aconsejable es, pero funciona.


Asynchronous UI Testing se introdujo en Xcode 7 Beta 4. Para esperar una etiqueta con el texto "¡Hola, mundo!" para aparecer puede hacer lo siguiente:

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)

Se pueden encontrar más detalles sobre las pruebas de IU en mi blog.


De acuerdo con la API para XCUIElement .exists se puede usar para verificar si existe una consulta o no, ¡así la siguiente sintaxis podría ser útil en algunos casos!

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

Si está seguro de que su expectativa se cumplirá eventualmente, podría intentar ejecutar esto. Cabe señalar que el bloqueo podría ser preferible si la espera es demasiado larga, en cuyo caso waitForExpectationsWithTimeout(_,handler:_) de la publicación de @Joe Masilotti debe usarse.


El siguiente código simplemente funciona con el objetivo 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]; }

Simplemente llame a esta función como se indica a continuación.

[self wait: 10];


En mi caso, el sleep creó efectos secundarios, así que usé

XCTWaiter.wait(for: [XCTestExpectation(description: "Hello World!")], timeout: 2.0)


Según share , he usado esta extensión:

extension XCTestCase { // Based on https://.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) } } } }

Puedes usarlo así

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

También permite esperar que un elemento desaparezca o que cambie cualquier otra propiedad (utilizando el bloque apropiado)

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


Editar:

En realidad, se me ocurrió que en Xcode 7b4, las pruebas de IU ahora tienen expectationForPredicate:evaluatedWithObject:handler: EvaluationWithObject expectationForPredicate:evaluatedWithObject:handler:

Original:

Otra forma es hacer girar el ciclo de ejecución durante un período de tiempo determinado. Realmente solo es útil si sabe cuánto tiempo (estimado) necesitará esperar

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

Esto no es súper útil si necesita probar algunas condiciones para continuar su prueba. Para ejecutar comprobaciones condicionales, use un ciclo while.


Xcode 9 introdujo nuevos trucos con XCTWaiter

El caso de prueba espera explícitamente

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

Delegados de instancia de camarero para probar

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

La clase de camarero devuelve el resultado

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 }

uso de muestra

Antes de Xcode 9

C objetivo

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

USO

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

Rápido

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

USO

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

o

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

SOURCE


iOS 11 / Xcode 9

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

¡Este es un gran reemplazo para todas las implementaciones personalizadas en este sitio!

Asegúrese de consultar mi respuesta aquí: https://.com/a/48937714/971329 . ¡Allí describo una alternativa a la espera de solicitudes que reducirá en gran medida el tiempo de ejecución de sus pruebas!