Slide 1

Slide 1 text

Asyncronous Testing in XCTest

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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ඵະຬͰςετࣦഊ }

Slide 4

Slide 4 text

XCTestExpectation • expectedFulfillmentCount • isInverted

Slide 5

Slide 5 text

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)

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

XCTWaiter

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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(" ! λΠϜΞ΢τͷ৔߹͸ͪ͜Β") } }

Slide 11

Slide 11 text

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)

Slide 12

Slide 12 text

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ͷॱং·ͰݟΔ͜ͱ͕Ͱ͖Δ

Slide 13

Slide 13 text

৭ʑͳExpectationୡ

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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)

Slide 16

Slide 16 text

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)

Slide 17

Slide 17 text

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)

Slide 18

Slide 18 text

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)

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Ҏ্