Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Asynchronous Testing in XCTest

Shingo Tamaki
December 21, 2018

Asynchronous Testing in XCTest

This document explain about asynchronous testing in XCTest

Shingo Tamaki

December 21, 2018
Tweet

More Decks by Shingo Tamaki

Other Decks in Technology

Transcript

  1. Asyncronous Testing
    in XCTest

    View Slide

  2. XCTestʹ͓͚Δඇಉظॲཧͷςετ
    ඇಉظͷςετͷͨΊʹXCTestExpectationͱXCTWaiter༻ҙ͞
    Ε͍ͯ·͢ɻ
    XCTestExpectationͷfulfillͷ࣮ߦΛ࣋ͬͯඇಉظॲཧͷ׬ྃͱ͠
    waitͰࢦఆͨ͠expectationͷ׬ྃʹ଴ػ͢Δͷ͕جຊతͳྲྀΕ
    Ͱ͢ɻ
    • XCTestExpectation
    • XCTWaiter

    View Slide

  3. XCTestExpectation
    func test_fetchPilot() {
    // 1.XCTestExpectationΛ࡞੒
    let expectation = XCTestExpectation(description: "pilot")
    PilotApiClient.fetchPilot(of: "new_type") { (result) in
    switch result {
    case .success(let user):
    XCTAssert(user.name == "REI")
    case .failure(_):
    break
    }
    // 2.ඇಉظॲཧͷ࣮ߦϒϩοΫͰfulfillΛ࣮ߦ
    expectation.fulfill()
    }
    // 3.waitؔ਺ʹexpectationΛࢦఆ
    wait(for: [expectation], timeout: 2) //<- 1ඵະຬͰςετࣦഊ
    }

    View Slide

  4. XCTestExpectation
    • expectedFulfillmentCount
    • isInverted

    View Slide

  5. XCTestExpectation
    expectedFulfillmentCountʹճ਺Λࢦఆ͢Δͱࢦఆճ਺ҎԼ͸
    λΠϜΞ΢τͰςετࣦഊͱ͞Ε·͢ɻ
    /// RadarAPIClient͔Β͸·ͣ1ඵޙʹɺͦͯͦ͠Ε͔Β5ඵޙʹίʔϧόοΫ͕ฦ͖ͬͯ·͢ɻ
    /// ෳ਺ճίʔϧόοΫ͕࣮ߦ͞ΕΔ఺Λߟྀͯ͠Έ·͠ΐ͏
    !
    let expectation = XCTestExpectation(description: "radar")
    expectation.expectedFulfillmentCount = 2
    let here = MyLocation(latitude: 35.664584, longitude: 139.730852)
    RadarApiClient.observeEnemy(from: here) { [expectation] (result) in
    switch result {
    case .success(let enemies):
    XCTAssert(enemies.count > 0)
    case .failure(_):
    break
    }
    expectation.fulfill()
    }
    wait(for: [expectation], timeout: 10)

    View Slide

  6. XCTestExpectation
    isInvertedΛࢦఆ͢ΔͱfulfillΛ"࣮ߦ͞Εͳ͍৔߹"ʹςετ͕੒
    ޭ͠·͢ɻ
    let expectation = XCTestExpectation(description: "inverted")
    expectation.isInverted = true // fulfill͕ى͖ͳ͔ͬͨ৔߹ʹςετ੒ޭͱ͢Δ
    wait(for: [expectation], timeout: 1)

    View Slide

  7. XCTWaiter

    View Slide

  8. XCTWaiter
    ͔͜͜Β͸XCTWaiterͷ࿩Λ͠·͢ɻ
    XCTWaiter͸waitϝιουͳͲͷΑ͏ͳඇಉظॲཧͷ׬ྃΛ଴
    ͭͨΊͷॲཧʹ͍ͭͯͷػೳΛ୲౰͠·͢ɻ
    ྫ͑͹wait͸XCTWaiterDelegateͰఆٛ͞Ε͓ͯΓɺ
    XCTestCase͕͜Εʹ४ڌ͍ͯ͠·͢ɻ

    View Slide

  9. wait(or waitForExpectations)
    • ॲཧ׬ྃ࣌ʹಛఆͷॲཧΛ࣮ߦ͍ͨ͠৔߹
    • ඇಉظॲཧͷλΠϜΞ΢τ͕ҟͳΔ৔߹
    • ඇಉظॲཧͷऴྃॱ͕৚݅ͱͳΔ৔߹(enforceOrder)

    View Slide

  10. wait(or waitForExpectations)
    ॲཧ׬ྃ࣌ʹಛఆͷॲཧΛ࣮ߦ͍ͨ͠৔߹
    let expectation = self.expectation(description: "waitExpectations")
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    expectation.fulfill() //fulfillͳͩ͠ͱ.timeoutWhileWaitingʹͳΔ
    }
    // ίʔϧόοΫͷҾ਺͸Error?Ͱ͋Γɺਖ਼ৗ࣌͸λΠϜΞ΢τ࣌͸XCTestError͕ฦ٫͞ΕΔ
    waitForExpectations(timeout: 1) { (error) in
    guard let error = error as? XCTestError else {
    return
    }
    switch error.code {
    case .failureWhileWaiting:
    print("
    !
    ࣦഊ࣌͸ͪ͜Β") //ਖ਼௚ίϨͷى͜͠ํ͕Θ͔ͬͯͳ͍
    break
    case .timeoutWhileWaiting:
    print("
    !
    λΠϜΞ΢τͷ৔߹͸ͪ͜Β")
    }
    }

    View Slide

  11. wait(or waitForExpectations)
    ඇಉظॲཧͷλΠϜΞ΢τ͕ҟͳΔ৔߹
    ҰͭͷwaitͰॲཧͤͣʹෳ਺ͷwaitΛ࢖͏ࣄͰλΠϜΞ΢τͷ࣌
    ؒΛ෼͚Δ͜ͱ͕Ͱ͖Δɻ
    let expForPilot = XCTestExpectation(description: "pilot")
    fetchPilot(expForPilot)
    let expForColony = XCTestExpectation(description: "colony")
    fetchColony(expForColony)
    // λΠϜΞ΢τͷ͕࣌ؒҧ͏ͷͰ͋Ε͹waitؔ਺Λෳ਺ʹ෼͚࣮ͯߦ͢Δࣄ΋ग़དྷΔɻ
    wait(for: [expForPilot], timeout: 2)
    wait(for: [expForColony], timeout: 4)

    View Slide

  12. wait(or waitForExpectations)
    ಛఆͷॱ൪Λظ଴ͯ͠ςετ͢Δ৔߹enforceOrderΛtrueʹ͢
    ΔࣄͰ࣮ߦ׬ྃॱग़ͳ͍৔߹ʹςετࣦഊͱ͢Δ͜ͱ͕Ͱ͖
    Δɻ
    let expForPilot = XCTestExpectation(description: "pilot")
    let expForColony = XCTestExpectation(description: "colony")
    // ྫ͑͹fetchColonyͷޙʹfetchPilot͠ͳ͚Ε͹͍͚ͳ͍ཁ͕݅͋ͬͨ৔߹
    fetchColony(expForColony) {
    fetchPilot(expForPilot)
    }
    wait(for: [expForColony, expForPilot],
    timeout: 10,
    enforceOrder: true) //<- enforceOrderΛࢦఆ͢ΔࣄͰexpectationͷॱং·ͰݟΔ͜ͱ͕Ͱ͖Δ

    View Slide

  13. ৭ʑͳExpectationୡ

    View Slide

  14. ৭ʑͳExpectationୡ
    • XCTKVOExpectation
    • XCTNSNotificationExpectation
    • XCTNSPredicateExpectation
    • XCTDarwinNotificationExpectation

    View Slide

  15. XCTKVOExpectation
    KVO(Key Value Observe)Λར༻ͨ͠Expectation
    KeyPathʹࢦఆͨ͠ϓϩύςΟͷ؂ࢹΛߦ͏ࣄͰར༻Մೳ
    let noobPilot = Pilot(id: "noob", name: "Arbeo", abilities: [])
    let battleField = BattleField(pilots: [noobPilot])
    let expectation = XCTKVOExpectation(keyPath: "mind", object: noobPilot)
    battleField.startBattle()
    wait(for: [expectation], timeout: 3)

    View Slide

  16. XCTNSNotificationExpectation
    NSNotificationΛར༻ͨ͠Expectation
    ࢦఆ໊ͨ͠લͷ௨஌Λ࣋ͬͯ׬ྃͱ͢Δࣄ͕Ͱ͖Δɻ
    let noobPilot = Pilot(id: "noob", name: "Arbeo", abilities: [])
    let battleField = BattleField(pilots: [noobPilot])
    let expectation = XCTNSNotificationExpectation(name: Notification.Name("΍ͬͯ΍Δʂ΍ͬͯ΍Δͧʂ"))
    battleField.startBattle()
    wait(for: [expectation], timeout: 3)

    View Slide

  17. XCTNSPredicateExpectation
    NSPredicateΛར༻ͨ͠Expectation
    ৚݅ʹ߹கΛॲཧ׬ྃͱ͢Δ͜ͱ͕Ͱ͖Δ
    let noobPilot = Pilot(id: "noob", name: "Arbeo", abilities: [])
    let battleField = BattleField(pilots: [noobPilot])
    let predicate = NSPredicate(format: "mind == 1")
    let expectation = XCTNSPredicateExpectation(predicate: predicate, object: noobPilot)
    battleField.startBattle()
    wait(for: [expectation], timeout: 3)

    View Slide

  18. XCTDarwinNotificationExpectatio
    n
    Darwin NotificationΛར༻ͨ͠Expectation
    NSNotificationͱಉ͘͡ࢦఆ໊ͨ͠લͷ௨஌Λ࣋ͬͯ׬ྃͱ͢Δ
    ࣄ͕Ͱ͖Δɻ
    let noobPilot = Pilot(id: "noob", name: "Arbeo", abilities: [])
    let battleField = BattleField(pilots: [noobPilot])
    let expectation = XCTDarwinNotificationExpectation(notificationName: "΍ͬͯΈΔ͞ʂ")
    battleField.startBattle()
    wait(for: [expectation], timeout: 3)

    View Slide

  19. ͓·͚
    Darwin Notify࢖͏ͱΞϓϦؒແࢹͯ͠௨஌͕Ͱ͖·͢ɻ
    ϦδΣΫτϦεΫ͸ݱࡏௐࠪதɺ·ͨվΊͯ࿩͠·͢ɻ଴ͯ࣍
    ճ

    View Slide

  20. Ҏ্

    View Slide