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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Shingo Tamaki
December 21, 2018
Technology
0
470
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
Use Gemini CLI from Claude Code as part of Sub Agent
tamaki
0
280
Let's make an Immersive Video with APMP
tamaki
0
46
Firebase Studioで始めるモバイルアプリ開発入門
tamaki
0
41
Introduction to Claude Code Action
tamaki
0
760
AIエージェントを使ったiOSアプリ開発を試してみた
tamaki
0
180
沖縄モバイルアプリ開発勉強会#1
tamaki
0
140
iOSアプリ開発を始めよう
tamaki
0
240
詳解xcresult.pdf
tamaki
0
420
メルペイでのリグレッションテスト自動化推進のこれまでとこれから
tamaki
0
810
Other Decks in Technology
See All in Technology
Oracle Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
5
1.1k
Digitization部 紹介資料
sansan33
PRO
1
7k
「使いにくい」も「運用疲れ」も卒業する UIデザイナーとエンジニアが創る持続可能な内製開発
nrinetcom
PRO
1
780
Ultra Ethernet (UEC) v1.0 仕様概説
markunet
3
190
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
4k
オンプレとGoogle Cloudを安全に繋ぐための、セキュア通信の勘所
waiwai2111
3
1.1k
All About Sansan – for New Global Engineers
sansan33
PRO
1
1.4k
Security Diaries of an Open Source IAM
ahus1
0
200
大規模サービスにおける レガシーコードからReactへの移行
magicpod
1
120
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
15
95k
パネルディスカッション資料 (at Tableau Now! - 2026-02-26)
yoshitakaarakawa
0
1.1k
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
44k
Featured
See All Featured
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
110k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.6k
Prompt Engineering for Job Search
mfonobong
0
180
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
63
Leo the Paperboy
mayatellez
4
1.5k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.9k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Embracing the Ebb and Flow
colly
88
5k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
80
It's Worth the Effort
3n
188
29k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
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͏ͱΞϓϦؒແࢹͯ͠௨͕Ͱ͖·͢ɻ ϦδΣΫτϦεΫݱࡏௐࠪதɺ·ͨվΊͯ͠·͢ɻͯ࣍ ճ
Ҏ্