Ik probeer een testcase te schrijven met behulp van de nieuwe UI Testing die beschikbaar is in Xcode 7 beta 2. De app heeft een inlogscherm waar hij naar de server belt om in te loggen. Er is een vertraging aan verbonden omdat het een asynchrone bewerking is.
Is er een manier om een vertragings- of wachtmechanisme in de XCTestCase te veroorzaken voordat verder wordt gegaan met verdere stappen?
Er is geen goede documentatie beschikbaar en ik heb de Header-bestanden van de klassen doorgenomen. Kon hier niets over vinden.
Ideeën/suggesties?
Antwoord 1, autoriteit 100%
Bovendien kun je gewoon slapen:
sleep(10)
Omdat de UITests in een ander proces draaien, werkt dit. Ik weet niet hoe raadzaam het is, maar het werkt.
Antwoord 2, autoriteit 74%
Asynchrone UI-testen is geïntroduceerd in Xcode 7 Beta 4. Wachten op een label met de tekst “Hallo, wereld!” om te verschijnen kunt u het volgende doen:
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)
Meer details over UI-testenzijn te vinden op mijn blog.
Antwoord 3, autoriteit 38%
iOS 11 / Xcode 9
<#yourElement#>.waitForExistence(timeout: 5)
Dit is een geweldige vervanging voor alle aangepaste implementaties op deze site!
Bekijk mijn antwoord hier: https://stackoverflow.com/a/48937714/971329. Daar beschrijf ik een alternatief voor het wachten op verzoeken, waardoor de tijd dat uw tests worden uitgevoerd aanzienlijk wordt verkort!
Antwoord 4, autoriteit 4%
Bewerken:
Het viel me eigenlijk net op dat in Xcode 7b4, UI-testen nu heeft
expectationForPredicate:evaluatedWithObject:handler:
Origineel:
Een andere manier is om de loop voor een bepaalde tijd te laten draaien. Echt alleen handig als je weet hoeveel (geschatte) tijd je moet wachten
Obj-C:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: <<time to wait in seconds>>]]
Snel:
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate(timeIntervalSinceNow: <<time to wait in seconds>>))
Dit is niet erg handig als u bepaalde voorwaarden moet testen om door te gaan met uw test. Gebruik een while
-lus om voorwaardelijke controles uit te voeren.
Antwoord 5, autoriteit 4%
Dit zal een vertraging veroorzaken zonder de thread in de sluimerstand te zetten of een foutmelding te geven bij time-out:
let delayExpectation = XCTestExpectation()
delayExpectation.isInverted = true
wait(for: [delayExpectation], timeout: 5)
Omdat de verwachting omgekeerd is, zal deze stil verlopen.
Antwoord 6, autoriteit 3%
Xcode testen Wacht
In mijn geval veroorzaakte sleep
een bijwerking, dus gebruikte ik wait
let _ = XCTWaiter.wait(for: [XCTestExpectation(description: "Hello World!")], timeout: 2.0)
Antwoord 7, autoriteit 2%
Hoe we het bij mijn huidige bedrijf doen, is dat we een XCUIElement-uitdrukkingsverwachting creëren (om een veelzijdige wachtmethode te creëren). We doen het op de volgende manier om ervoor te zorgen dat het onderhoudbaar is (veel variatie in verwachtingen, en we willen niet veel methoden/specifieke predikaten maken om dit te doen.
Swift 5
Basismethode
De uitdrukking wordt gebruikt om een dynamische predikaatwaarde te vormen. We kunnen XCTNSPredicateExpectation
‘s maken van predikaten, die we vervolgens doorgeven aan XCTWaiter
om expliciet te wachten. Als het resultaat iets anders was dan completed
, dan falen we met een optioneel bericht.
@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
}
Gebruik
app.buttons["my_button"].wait(until: { $0.exists })
app.buttons["my_button"].wait(until: { $0.isHittable })
Toetsenpaden
Vervolgens verpakken we dat in een methode waarbij een keyPath en match
-waarde de expressie vormen.
@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
)
}
Gebruik
app.buttons["my_button"].wait(until: \.exists, matches: true)
app.buttons["my_button"].wait(until: \.isHittable, matches: false)
Vervolgens kun je die methode inpakken, waarbij de waarde match
altijd true
is voor een gebruik dat ik het meest heb gevonden.
Gebruik
app.buttons["my_button"].wait(until: \.exists)
app.buttons["my_button"].wait(until: \.isHittable)
Ik heb er een bericht over geschreven en krijg daar ook het volledige extensiebestand: https: //sourcediving.com/clean-waiting-in-xcutest-43bab495230f
Antwoord 8, autoriteit 2%
De volgende code werkt alleen met 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];
}
Bel gewoon deze functie aan zoals hieronder aangegeven.
[self wait: 10];
Antwoord 9
sleep blokkeert de thread
“Er vindt geen run loop-verwerking plaats terwijl de thread is geblokkeerd.”
u kunt waitForExistence gebruiken
let app = XCUIApplication()
app.launch()
if let label = app.staticTexts["Hello, world!"] {
label.waitForExistence(timeout: 5)
}
Antwoord 10
Volgens de API voor XCUIElement kan .exists
worden gebruikt om te controleren of een query bestaat of niet, dus de volgende syntaxis kan in sommige gevallen nuttig zijn!
let app = XCUIApplication()
app.launch()
let label = app.staticTexts["Hello, world!"]
while !label.exists {
sleep(1)
}
Als u er zeker van bent dat uw verwachting uiteindelijk zal worden waargemaakt, kunt u proberen dit uit te voeren. Opgemerkt moet worden dat crashen de voorkeur heeft als het wachten te lang is, in welk geval waitForExpectationsWithTimeout(_,handler:_)
uit de post van @Joe Masilotti moet worden gebruikt.
Antwoord 11
let app = XCUIApplication()
app.launch()
//Find the button in the UI
let SettingsButton =
app.navigationBars["HomeView"].buttons["Settings"]
XCTAssertTrue(settingButton.waitForExistence(timeout: 10))