Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
不安定なテストは200種類あんねん
Search
yimajo
October 27, 2023
Programming
1.3k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
不安定なテストは200種類あんねん
#ios_test_night
https://testnight.connpass.com/event/295913/
yimajo
October 27, 2023
More Decks by yimajo
See All by yimajo
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
390
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
930
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
750
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
1
410
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
3
360
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発ユニットテストの場合
yimajo
22
6.9k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
2.8k
Swift 5.9 からの Observation はiOS17 未満 からも使えて struct の変更検知もできるんすかね?
yimajo
2
1.2k
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
2.1k
Other Decks in Programming
See All in Programming
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.4k
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
380
Agents on Rails - Rails at Scale 2026
irinanazarova
0
320
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
450
FreeBSDでZabbixを動かす
kenkino
0
350
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
230
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
380
Rでドレミ/Do-Re-Mi_with_R
florets1
0
110
Security issues being discussed on Web Platforms
petamoriken
0
1.4k
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
170
mrbgem 三角測量 開発
ogom
0
180
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
250
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.1k
Writing Fast Ruby
sferik
630
63k
Google's AI Overviews - The New Search
badams
0
1.6k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
750
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
340
Building Applications with DynamoDB
mza
96
7.2k
Building an army of robots
kneath
307
47k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
66k
RailsConf 2023
tenderlove
30
1.6k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
520
Transcript
ෆ҆ఆͳςετछྨ͋ΜͶΜ #ios_test_night 2023.10 y.imajo
ࣗݾհ
ࣗݾհ • ৬ྺ • ৽ଔ: ಋମϝʔΧʔͰςετΤϯδχΞ • WebϞόΠϧΞϓϦ։ൃͷιϑτΣΞΤϯδχΞ • Now!:
ϓϩαφʔ݉ιϑτΣΞΤϯδχΞ
ຊ ෆ҆ఆͳςετͷݪҼΛཧ ͠ղܾ͢ΔҊ
ࠓճࢲ͕͢ʮෆ҆ఆͳςετʯͷఆٛ • ςετίʔυʹΑΓςετࣗಈԽ͞Εɺͦͷ݁Ռ͕ޭͨ͠Γࣦഊ͠ ͨΓͱෆ҆ఆͳ୯ମςετͷ͜ͱ • ඞͣޭ͢Δ୯ମςετෆ҆ఆͰͳ͍ • ඞࣦͣഊ͢Δ୯ମςετෆ҆ఆͰͳ͍
ࢲͷʮෆ҆ఆͳςετʯͷఆٛ ޭ ࣦഊ ෆ҆ఆͳςετ ʢݪҼ͍͍ͩͨݟΔਓʹΑͬͯʣ200छྨ͋ΜͶΜ
ݪҼͷྨ • େྨ1: ςετίʔυ·ͨςετରͷϓϩμΫγϣϯίʔυ͕ѱ͍ • ݪҼ1: ࣮ߦ࣌ʹܾఆ͢ΔಈతͳʹΑΔςετ࣮ߦ • ݪҼ2: OSSϑϨʔϜϫʔΫཧղෆ
• ݪҼ3: ςετέʔεͷ࣮ߦॱংґଘ • ݪҼ4: ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ • ݪҼ ͦͷଞ • େྨ2: ςετ࣮ߦϚγϯཁҼʢڥʣ ࠓ͢͜ͱ
ݪҼ1: ࣮ߦ࣌ʹܾఆ͢ΔಈతͳʹΑΔςετ࣮ߦ • ྫ • Foundation.Date.init() / Foundation.Date.now • ݺͼग़͞Εͨࡍͷ࣌ؒΛऔಘ͢Δίʔυ
ྫ: Foundation.Date.init() / Foundation.Date.now • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ݻఆͰͳ͍ͨΊ • ݱࡏ࣌ࠁͷ༻ҙ͔Βར༻͢Δ·Ͱఆ֎ʹ͕࣌ؒܦա͢Δ
• ͲͷΑ͏ͳ߹ʹࠔΔͷ͔ • ςετରͷϝιουͰNඵҎͳͲͷॲཧ͕͋Δ • ςετίʔυࣗମͰͷൺֱʹ͏ͷ͔͍ͬ • Ͳ͏ղܾ͢Δͷ͔ • Date.init()/Date.nowʹΑΔݱࡏ࣌ࠁऔಘ෭࡞༻࣮ߦͱߟ͑ɺDIͨ͠ͷΛར༻͢Δ • Ͱ͖Δ͚ͩݻఆʢfixtureʣΛ͏ ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹܾఆ͢ΔಈతͳʹΑΔςετ࣮ߦ
ิ: ࣮ߦ࣌ʹಈతʹ͕ܾఆ͢ΔͭΒ • Foundation.Date / Calendar / Locale / UUID
• Swift Standard LibraryͷContinuousClock • ͳͲͷཚੜ ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹܾఆ͢ΔಈతͳʹΑΔςετ࣮ߦ https://github.com/pointfreeco/swift-dependencies/tree/main/ Sources/Dependencies/DependencyValues ࢀߟ: pointfreeco/swift-dependencies
ݪҼ2: OSSϑϨʔϜϫʔΫཧղෆ • ྫ • QuickͰDate()ΛbeforeEachΘͣݺͼग़ͯ͠͠·͏ • RxSwiftͰεέδϡʔϥΛDIͤͣʹςετͯ͠͠·͏ • OHHTTPStubs
/ AutoMockable • ࠓճআ֎
ྫ: QuickͰDate()ΛbeforeEachΘͣݺͼग़ͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • Quickςετ࣮ߦͷͨΊʹ·ͣ༻ҙͯ͋͠ΔQuickSpecશ͕ͯॳ ظԽ͞ΕɺςετରΛूΊͨ͋ͱʹςετΛॱ࣮࣍ߦ͢Δ • ݱࡏ࣌ࠁͷ༻ҙ͔Βར༻͢Δ·Ͱఆ֎ʹ͕࣌ؒܦա͢Δ •
Ͳ͏ղܾ͢Δͷ͔ • beforeEach͏ ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ
class SpecA: QuickSpec { override class func spec() { describe("A")
{ print("A.describe") let date = Date() // beforeEachΛΘͳ͍ྫ it("actionϝιου1ඵҎʹ࣮ߦ͕ྃ͢Δ") { print("A.it") let subject = ... subject.action() expect(date - Date()) < 1.0 // ྫ } } } } class SpecB: QuickSpec { override class func spec() { describe(“B") { print("B.describe") it(“…”) { print("B.it") } } } } A.describe B.describe A.it B.it it࠷ޙʹ࣮ߦ͞ΕΔ • SpecAͷspecϝιου͕࣮ߦ͞ΕΔ • SpecAͷdescribe͕࣮ߦ͞ΕΔ • SpecBͷspecϝιου͕࣮ߦ͞ΕΔ • SpecBͷdescribe͕࣮ߦ͞ΕΔ • SpecAͷit͕࣮ߦ͞ΕΔ • SpecBͷit͕࣮ߦ͞ΕΔ print ݁Ռ
ͳΜͰ͜Μͳ͜ͱʹ…?
XcodeͰͷςετ࣮ߦ (xcodebuild test ܥ) ϑΣʔζͱͯ͠ ςετͷ ొ ͱ ࣮ߦ
ͷ2ϑΣʔζʹ ͔Ε͍ͯͯ Quick ͦΕΛར༻͍ͯ͠Δɻ ςετొϑΣʔζ ςετ࣮ߦϑΣʔζ XCTestCaseͷdefaultTestSuite XCTestCaseͷtestInvocations ิBQQMFTXJGUUFTUJOHͰݱঢ়ςετొͯ͠ΔΓํͱҧ͏
XCTest Quick ϑΣʔζ1. XcodeXCTestCaseΛܧঝͨ͠Πϯελϯε͔ΒdefaultTestSuiteΛ࣮ߦ͢Δ ϑΣʔζ1_1. defaultTestSuite͔ΒgatherExamplesNeeded()͕ݺͼग़͞ΕΔ ϑΣʔζ1_2. gatherExamplesNeeded()spec()Λ࣮ߦ ϑΣʔζ1_3. spec()ʹ͋ΔbeforeEach()/it()ΛWorldʹappend͍ͯ͘͠
ϑΣʔζ2. XcodeXCTestCaseܧঝ͍ͯ͠ΔΠϯελϯε͔ΒtestInvocationsΛ࣮ߦ͢Δ ϑΣʔζ2_1.testInvocationsWorldʹappend͞ΕͯΔͷ͔ΒऔΓग़͠itΛςετͱ࣮ͯ͠ߦ beforeEach/it४උϑΣʔζͰอ࣋͞Ε ࣮ߦϑΣʔζͰ࣮ߦ͞ΕΔ
͓·͚: ৗʹࣦഊ͢Δྫ Presenter͕ղ์͞Ε݁Ռࣦഊɻ itΫϩʔδϟ͕࣮ߦ͞ΕΔ࣌ ϑΣʔζ2Ͱ͋ΓɺϑΣʔζ1Ͱ࡞ ͞ΕͨPresenterࢀর͞Εͳ͍ͷ Ͱʢେʣղ์͞ΕΔ͜ͱͰdeinit ͕࣮ߦ͞Ε݁Ռ͕มΘΔɻ class SpecC:
QuickSpec { override class func spec() { describe(“Presenter.viewDidLoad࣮ߦ”) { // ·ͨbeforeEach͠ͳ͍ let spy = View() let presenter = Presenter() // SUT presenter.view = spy // Action४උϑΣʔζͰͬͯ͠·͏ presenter.viewDidLoad() ɹɹ it("Viewͷ͕ViewDidLoadͰtrueʹͳͬͯΔ") { expect(spy.flag).to(beTrue()) // ݁Ռʁ } } } } class Presenter { var view: View? deinit { view?.flag = false } func viewDidLoad() { view?.flag = true } }
ྫ: RxSwiftͰεέδϡʔϥΛDIͤͣςετͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • MainSchedulerಉظతʹΛྲྀ͢ͱ͖͋Δ͠ඇಉظతʹΛྲྀ ͢͜ͱ͋Δ • Ͳ͏ղܾ͢Δͷ͔ •
εέδϡʔϥΛDI͠ςετεέδϡʔϥΛ͏ • RxSwiftͷίʔυΛಡΉ͔RxSwiftݚڀಡຊΛങ͏ ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ
ݪҼ3: ςετέʔεͷ࣮ߦॱংґଘ • ྫ • ςετରΛෳςετέʔεͰ͍ճ͠ϓϩύςΟΛηοτ
ྫ: ςετରΛෳςετέʔεͰ͍ճ͠ϓϩύςΟΛηοτ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ςετରTest Doubleʹ͏ΦϒδΣΫτΛෳςετͰ͍ ճͯ͠͠·͏ͱͦͷϓϩύςΟΛηοτ͠ΕͨΓϦηοτ͠Ε Δ •
Ͳ͏ղܾ͢Δͷ͔ • ෳςετέʔεͰ͍·Θ͞ͳ͍ ෆ҆ఆͳݪҼ:ςετέʔεͷ࣮ߦॱংґଘ
class SpecD: QuickSpec { override class func spec() { describe(“ະఆ͢Δ")
{ var subject = … var user = TestDouble.User() context(“ॴ͕ຊͰ10ࡀ”) { beforeEach { user.age = 10 subject.user = user } it("ະఆ͞ΕΔ") { subject.action() expect(subject.ະ).to(beTruth)) } } context(“ॴҟੈքͰ10ࡀ”) { beforeEach { user.age = 10 subject.user = user subject.location = .ҟੈք } it(“ະఆ͞Εͳ͍") { subject.action() expect(subject.ະ).to(beFalse)) } } ྫ: ্ͷຊcontextͰlocationΛ ઃఆ͍ͯ͠ͳ͍͕σϑΥϧτͷ locationͰઌʹςετޭ͠ɺ࣍ ʹԼͷҟੈքcontextͰ໌ࣔͯ͠ ςετޭ͍ͯ͠Δͱ͢Δɻ ઌʹԼͷҟੈքcontext͕࣮ߦ͞Ε Δͱ…?
Quick ͕ѱ͍Θ͚͡Όͳ͘ɺςετରӨڹ Λٴ΅͢ΦϒδΣΫτ͕ςετ֎͔ΒӨڹΛड ͚Δ͜ͱΛՄೳʹͯ͠͠·͍ͬͯΕɺςετ ݁Ռҙਤͤͣෆ҆ఆʹͳΓ͍͢ɻ
ͨͩͪΐͬͱ͜Εʹؔͯ͠QuickΛͬͯͳ ͍ͱ͍͚ͳ͍͜ͱ͕ଟ͍͔ͳͱࢥ͏
ઌड़ͷ௨Γɺ QuickͰbeforeEach४උϑΣʔζͰͳ࣮͘ߦϑΣʔζͰ͋ ΓɺมͷॳظԽΒ࠶ઃఆʢArrangeʣͰ࣮֬ʹΘ͍ͤͨΜ ͚ͩͲɺbeforeEachΫϩʔδϟͳͷͰArrangeͷνΣοΫΛ͢ ΔΑ͏ͳػೳͳ͍ɻ
ܕͷػೳΛར༻ͯ͠ܕ҆৺ͳςετͷArrange͕Ͱ͖Εͬͱ ྑ͍ͱࢥ͑Δ…ɻ XCTestCaseࣗମͰؤுΕͰ͖Δɻ apple/swift-testingͬͨΒ͞Βʹදݱྗߴ͘Ͱ͖ͦ͏…ɻ
ݪҼ4: ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ • ྫ • ϝΠϯλʔήοτͰͷςετϗετΞϓϦέʔγϣϯ͕ىಈͯ͠ ͠·͏ • XCTestCase.waitϝιουʹΑΓεϨου͕σουϩοΫ͢Δͱ͖ ͕͋Δ
ྫ: ϝΠϯλʔήοτͰͷςετϗετΞϓϦέʔγϣϯ͕ىಈͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ઃఆͱͯ͠ɺςετϞδϡʔϧΛϗετΞϓϦຊମͱࢦఆ͢Δͱςετ࣌ʹΞϓϦ͕ ىಈ͠ɺͦ͜Ͱ෭࡞༻Λ࣮ߦ͠ςετʹӨڹΛ༩͑Δ͜ͱ͕͋Δ • Ͳ͏ղܾ͢Δͷ͔ •
AppDelegateΛMockͯ͠Կ͠ͳ͍ʢor Mockͤͣݕ͠ذͯ͠Կ͠ͳ͍ʣ • ϗετΞϓϦͷϞδϡʔϧSwiftUI.AppAppDelegateͷΈ࣋ͪɺͦΕҎ֎ͷॲཧ Ϟδϡʔϧͱׂ͠ɺͦΕʹରͯ͠ςετλʔήοτϞδϡʔϧΛ࡞Δ • XcodeઃఆͰHost Application = Noneʹͯ͠ςετ࣮ߦͰ͖Ε͍͍ ෆ҆ఆͳݪҼ:ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ
ϝΠϯλʔήοτ ϝΠϯλʔήοτͷ ςετλʔήοτ )PTU"QQMJDBUJPOϝΠϯλʔήοτ ςετ࣮ߦͰ)PTU"QQMJDBUJPO͋ΔΜͰ ΞϓϦέʔγϣϯ͕ىಈ࣮ߦ͢Δɻ JNQPSU 1BDLBHFͷ ςετλʔήοτ λʔήοτ
JNQPSU 1BDLBHFTXJGU JNQPSU YDXPSLTQBDF ิYDPEFCVJMEͰͷςετͰ͋ΓTXJGUUFTU࣮ߦͰͷςετʹ͍ͭͯͷͰ͋Γ·ͤΜ &NCFEEFE'SBNFXPSL λʔήοτ &NCFEEFE.PEVMFͷ ςετλʔήοτ )PTU"QQMJDBUJPO/POF ςετ࣮ߦͰ)PTU"QQMJDBUJPO͕ͳ͍ͳΒɺ ΞϓϦέʔγϣϯىಈ࣮ߦ͠ͳ͍ɻ JNQPSU
ྫ: XCTestCase.waitϝιουʹΑΓεϨου͕σουϩοΫ͢Δͱ͖͕͋Δ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • wait Ͱ Task { @MainActor
in } ͷ݁ՌΛͭςετͳ߹ɺwaitϏδʔΣΠτ͞ ͤͯϝΠϯεϨουΛࢭΊ͍ͯΔͨΊɺTaskͷϝΠϯεϨου࣮ߦΛ્͢Δͪ ͔ͨͱͳΓσουϩοΫ • Ͳ͏ղܾ͢Δͷ͔ • ͦͦXcode 14.3ܥͰܯࠂ͞ΕΔ • Swift ConcurrencyΛ͏߹ fulfillment(of:timeout:…) ϝιου͕༻ҙ͞Ε͍ͯΔ ෆ҆ఆͳݪҼ:ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ
XCTest.framwork ͷίʔυGitHubͰެ։͞Ε͍ͯΔͷͰಡΊΘ͔Δͣ
͓ΘΓʹ
͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ ҙݟ͕͋ͬͨΒͰ͖Δ͚ͩͳΔ͘ Θ͔Γ͘͢ࢦఠ࣭ͯ͠Β͑Δͱ ༗ҙٛͳΓͱΓ͕Ͱ͖ΔͣͰ͢