Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Asynchronous Testing in XCTest
Search
Shingo Tamaki
December 21, 2018
Technology
0
420
Asynchronous Testing in XCTest
This document explain about asynchronous testing in XCTest
Shingo Tamaki
December 21, 2018
Tweet
Share
More Decks by Shingo Tamaki
See All by Shingo Tamaki
AIエージェントを使ったiOSアプリ開発を試してみた
tamaki
0
66
沖縄モバイルアプリ開発勉強会#1
tamaki
0
110
iOSアプリ開発を始めよう
tamaki
0
170
詳解xcresult.pdf
tamaki
0
340
メルペイでのリグレッションテスト自動化推進のこれまでとこれから
tamaki
0
730
What do you want to test with UI Test v2
tamaki
2
890
JPQRによって変わる日本のQRコード決済
tamaki
0
290
What's New in Testing
tamaki
1
58
What do you want to test with UI Test
tamaki
5
1.9k
Other Decks in Technology
See All in Technology
Google Cloud Next 2025 Recap マーケティング施策の運用及び開発を支援するAIの活用 / Use of AI to support operation and development of marketing campaign
atsushiyoshikawa
0
270
製造業向けIoTソリューション提案資料.pdf
haruki_uiru
0
280
Tailwind CSS の小話「コンテナークエリーって便利」
yamaday
0
130
非root化Androidスマホでも動く仮想マシンアプリを試してみた
arkw
0
130
ユーザーコミュニティが海外スタートアップのDevRelを補完する瞬間
nagauta
1
200
使えるデータ基盤を作る技術選定の秘訣 / selecting-the-right-data-technology
pei0804
9
1.5k
猫でもわかるS3 Tables【Apache Iceberg編】
kentapapa
2
230
テストコードにはテストの意図を込めよう(2025年版) #retechtalk / Put the intent of the test 2025
nihonbuson
PRO
10
1.8k
20250514 1Passwordを使い倒す道場 vol.1
east_takumi
0
130
正式リリースされた Semantic Kernel の Agent Framework 全部紹介!
okazuki
1
1.2k
Part1 GitHubってなんだろう?その2
tomokusaba
2
800
Global Azure2025(GitHub Copilot ハンズオン)
tomokusaba
2
810
Featured
See All Featured
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
179
53k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Designing for humans not robots
tammielis
253
25k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.2k
Scaling GitHub
holman
459
140k
Building Adaptive Systems
keathley
41
2.5k
[RailsConf 2023] Rails as a piece of cake
palkan
54
5.5k
Code Review Best Practice
trishagee
68
18k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
The World Runs on Bad Software
bkeepers
PRO
68
11k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
357
30k
Transcript
Asyncronous Testing in XCTest
XCTestʹ͓͚Δඇಉظॲཧͷςετ ඇಉظͷςετͷͨΊʹXCTestExpectationͱXCTWaiter༻ҙ͞ Ε͍ͯ·͢ɻ XCTestExpectationͷfulfillͷ࣮ߦΛ࣋ͬͯඇಉظॲཧͷྃͱ͠ waitͰࢦఆͨ͠expectationͷྃʹػ͢Δͷ͕جຊతͳྲྀΕ Ͱ͢ɻ • XCTestExpectation • XCTWaiter
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ඵະຬͰςετࣦഊ }
XCTestExpectation • expectedFulfillmentCount • isInverted
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)
XCTestExpectation isInvertedΛࢦఆ͢ΔͱfulfillΛ"࣮ߦ͞Εͳ͍߹"ʹςετ͕ ޭ͠·͢ɻ let expectation = XCTestExpectation(description: "inverted") expectation.isInverted =
true // fulfill͕ى͖ͳ͔ͬͨ߹ʹςετޭͱ͢Δ wait(for: [expectation], timeout: 1)
XCTWaiter
XCTWaiter ͔͜͜ΒXCTWaiterͷΛ͠·͢ɻ XCTWaiterwaitϝιουͳͲͷΑ͏ͳඇಉظॲཧͷྃΛ ͭͨΊͷॲཧʹ͍ͭͯͷػೳΛ୲͠·͢ɻ ྫ͑waitXCTWaiterDelegateͰఆٛ͞Ε͓ͯΓɺ XCTestCase͕͜Εʹ४ڌ͍ͯ͠·͢ɻ
wait(or waitForExpectations) • ॲཧྃ࣌ʹಛఆͷॲཧΛ࣮ߦ͍ͨ͠߹ • ඇಉظॲཧͷλΠϜΞτ͕ҟͳΔ߹ • ඇಉظॲཧͷऴྃॱ͕݅ͱͳΔ߹(enforceOrder)
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(" ! λΠϜΞτͷ߹ͪ͜Β") } }
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)
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ͷॱং·ͰݟΔ͜ͱ͕Ͱ͖Δ
৭ʑͳExpectationୡ
৭ʑͳExpectationୡ • XCTKVOExpectation • XCTNSNotificationExpectation • XCTNSPredicateExpectation • XCTDarwinNotificationExpectation
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)
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)
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)
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)
͓·͚ Darwin Notify͏ͱΞϓϦؒແࢹͯ͠௨͕Ͱ͖·͢ɻ ϦδΣΫτϦεΫݱࡏௐࠪதɺ·ͨվΊͯ͠·͢ɻͯ࣍ ճ
Ҏ্