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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
yimajo
October 27, 2023
Programming
3
1.1k
不安定なテストは200種類あんねん
#ios_test_night
https://testnight.connpass.com/event/295913/
yimajo
October 27, 2023
Tweet
Share
More Decks by yimajo
See All by yimajo
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
630
いま中途半端なSwift 6対応をするより、Default ActorやApproachable Concurrencyを有効にしてからでいいんじゃない?
yimajo
2
590
11年かかって やっとVibe Codingに 時代が追いつきましたね
yimajo
1
350
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
2
300
良いテストコードのために悪いテストコードを理解する - 不安定なテスト編: iOSアプリ開発ユニットテストの場合
yimajo
22
6.5k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
2.5k
Swift 5.9 からの Observation はiOS17 未満 からも使えて struct の変更検知もできるんすかね?
yimajo
2
1.1k
TCA v0.19.0からのSwitchStore/CaseLetが良い
yimajo
0
2k
TCAでViewStoreにKeyPath DynamicMemberLookupが使われてる件
yimajo
0
1.2k
Other Decks in Programming
See All in Programming
OCaml 5でモダンな並列プログラミングを Enjoyしよう!
haochenx
0
140
MUSUBIXとは
nahisaho
0
140
Unicodeどうしてる? PHPから見たUnicode対応と他言語での対応についてのお伺い
youkidearitai
PRO
1
2.6k
Best-Practices-for-Cortex-Analyst-and-AI-Agent
ryotaroikeda
1
110
CSC307 Lecture 01
javiergs
PRO
0
690
Raku Raku Notion 20260128
hareyakayuruyaka
0
370
生成AIを使ったコードレビューで定性的に品質カバー
chiilog
1
280
izumin5210のプロポーザルのネタ探し #tskaigi_msup
izumin5210
1
140
Amazon Bedrockを活用したRAGの品質管理パイプライン構築
tosuri13
5
800
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
330
組織で育むオブザーバビリティ
ryota_hnk
0
180
MDN Web Docs に日本語翻訳でコントリビュート
ohmori_yusuke
0
660
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
269
14k
Producing Creativity
orderedlist
PRO
348
40k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
170
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.3k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
1
300
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
57
Side Projects
sachag
455
43k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
3.9k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.3k
Heart Work Chapter 1 - Part 1
lfama
PRO
5
35k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.1k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
89
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Ͱެ։͞Ε͍ͯΔͷͰಡΊΘ͔Δͣ
͓ΘΓʹ
͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ ҙݟ͕͋ͬͨΒͰ͖Δ͚ͩͳΔ͘ Θ͔Γ͘͢ࢦఠ࣭ͯ͠Β͑Δͱ ༗ҙٛͳΓͱΓ͕Ͱ͖ΔͣͰ͢