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
不安定なテストは200種類あんねん
Search
yimajo
October 27, 2023
Programming
1.2k
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
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
880
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
690
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
1
390
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
3
330
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発ユニットテストの場合
yimajo
22
6.8k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
2.7k
Swift 5.9 からの Observation はiOS17 未満 からも使えて struct の変更検知もできるんすかね?
yimajo
2
1.2k
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
2k
TCAでViewStoreにKeyPath DynamicMemberLookupが使われてる件
yimajo
0
1.3k
Other Decks in Programming
See All in Programming
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
130
act1-costs.pdf
sumedhbala
0
230
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
320
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
150
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.8k
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
760
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
570
1年で人数1.5倍、PR数5.5倍増。 品質とアウトカムはどうなったか、 何が効いたか
ike002jp
0
140
初めてのKubernetes 本番運用でハマった話
oku053
0
130
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
2
1.5k
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
270
Featured
See All Featured
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
350
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
260
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
260
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.9k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
410
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
40k
Everyday Curiosity
cassininazir
0
260
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
220
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
190
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Ͱެ։͞Ε͍ͯΔͷͰಡΊΘ͔Δͣ
͓ΘΓʹ
͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ ҙݟ͕͋ͬͨΒͰ͖Δ͚ͩͳΔ͘ Θ͔Γ͘͢ࢦఠ࣭ͯ͠Β͑Δͱ ༗ҙٛͳΓͱΓ͕Ͱ͖ΔͣͰ͢