Slide 1

Slide 1 text

ෆ҆ఆͳςετ͸छྨ͋ΜͶΜ #ios_test_night 2023.10 y.imajo

Slide 2

Slide 2 text

ࣗݾ঺հ

Slide 3

Slide 3 text

ࣗݾ঺հ • ৬ྺ • ৽ଔ: ൒ಋମϝʔΧʔͰςετΤϯδχΞ • Web΍ϞόΠϧΞϓϦ։ൃͷιϑτ΢ΣΞΤϯδχΞ • Now!: ϓϩα΢φʔ݉ιϑτ΢ΣΞΤϯδχΞ

Slide 4

Slide 4 text

ຊ୊ ෆ҆ఆͳςετͷݪҼΛ੔ཧ ͠ղܾ͢ΔҊ

Slide 5

Slide 5 text

ࠓճࢲ͕࿩͢ʮෆ҆ఆͳςετʯͷఆٛ • ςετίʔυʹΑΓςετࣗಈԽ͞Εɺͦͷ݁Ռ͕੒ޭͨ͠Γࣦഊ͠ ͨΓͱෆ҆ఆͳ୯ମςετͷ͜ͱ • ඞͣ੒ޭ͢Δ୯ମςετ͸ෆ҆ఆͰ͸ͳ͍ • ඞࣦͣഊ͢Δ୯ମςετ͸ෆ҆ఆͰ͸ͳ͍

Slide 6

Slide 6 text

ࢲͷʮෆ҆ఆͳςετʯͷఆٛ ੒ޭ ࣦഊ ෆ҆ఆͳςετ ʢݪҼ͸͍͍ͩͨݟΔਓʹΑͬͯ͸ʣ200छྨ͋ΜͶΜ

Slide 7

Slide 7 text

ݪҼͷ෼ྨ • େ෼ྨ1: ςετίʔυ·ͨ͸ςετର৅ͷϓϩμΫγϣϯίʔυ͕ѱ͍ • ݪҼ1: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ • ݪҼ2: OSSϑϨʔϜϫʔΫཧղෆ଍ • ݪҼ3: ςετέʔεͷ࣮ߦॱংґଘ • ݪҼ4: ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍ • ݪҼ ͦͷଞ • େ෼ྨ2: ςετ࣮ߦϚγϯཁҼʢ؀ڥʣ ࠓ೔࿩͢͜ͱ

Slide 8

Slide 8 text

ݪҼ1: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ • ྫ • Foundation.Date.init() / Foundation.Date.now • ݺͼग़͞Εͨࡍͷ࣌ؒΛऔಘ͢Δίʔυ

Slide 9

Slide 9 text

ྫ: Foundation.Date.init() / Foundation.Date.now • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ݻఆ஋Ͱ͸ͳ͍ͨΊ • ݱࡏ࣌ࠁͷ༻ҙ͔Βར༻͢Δ·Ͱ૝ఆ֎ʹ͕࣌ؒܦա͢Δ • ͲͷΑ͏ͳ৔߹ʹࠔΔͷ͔ • ςετର৅ͷϝιου಺ͰNඵҎ಺ͳͲͷॲཧ͕͋Δ • ςετίʔυࣗମͰ஋ͷൺֱʹ࢖͏ͷ΋΍͔͍ͬ • Ͳ͏ղܾ͢Δͷ͔ • Date.init()/Date.nowʹΑΔݱࡏ࣌ࠁऔಘ͸෭࡞༻࣮ߦͱߟ͑ɺDIͨ͠΋ͷΛར༻͢Δ • Ͱ͖Δ͚ͩݻఆ஋ʢfixtureʣΛ࢖͏ ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ

Slide 10

Slide 10 text

ิ଍: ࣮ߦ࣌ʹಈతʹ஋͕ܾఆ͢Δ΍ͭΒ • Foundation.Date / Calendar / Locale / UUID • Swift Standard LibraryͷContinuousClock • ੔਺ͳͲͷཚ਺ੜ੒ ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ https://github.com/pointfreeco/swift-dependencies/tree/main/ Sources/Dependencies/DependencyValues ࢀߟ: pointfreeco/swift-dependencies

Slide 11

Slide 11 text

ݪҼ2: OSSϑϨʔϜϫʔΫཧղෆ଍ • ྫ • QuickͰDate()ΛbeforeEach࢖Θͣݺͼग़ͯ͠͠·͏ • RxSwiftͰεέδϡʔϥΛDIͤͣʹςετͯ͠͠·͏ • OHHTTPStubs / AutoMockable • ࠓճ͸আ֎

Slide 12

Slide 12 text

ྫ: QuickͰDate()ΛbeforeEach࢖Θͣݺͼग़ͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • Quick͸ςετ࣮ߦͷͨΊʹ·ͣ༻ҙͯ͋͠ΔQuickSpecશ͕ͯॳ ظԽ͞Εɺςετର৅ΛूΊͨ͋ͱʹςετΛॱ࣮࣍ߦ͢Δ • ݱࡏ࣌ࠁͷ༻ҙ͔Βར༻͢Δ·Ͱ૝ఆ֎ʹ͕࣌ؒܦա͢Δ • Ͳ͏ղܾ͢Δͷ͔ • beforeEach࢖͏ ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ଍

Slide 13

Slide 13 text

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 ݁Ռ

Slide 14

Slide 14 text

ͳΜͰ͜Μͳ͜ͱʹ…?

Slide 15

Slide 15 text

XcodeͰͷςετ࣮ߦ (xcodebuild test ܥ) ͸ ϑΣʔζͱͯ͠ ςετͷ ొ࿥ ͱ ࣮ߦ ͷ2ϑΣʔζʹ ෼͔Ε͍ͯͯ Quick ͸ͦΕΛར༻͍ͯ͠Δɻ ςετొ࿥ϑΣʔζ ςετ࣮ߦϑΣʔζ XCTestCaseͷdefaultTestSuite XCTestCaseͷtestInvocations ิ଍BQQMFTXJGUUFTUJOHͰݱঢ়ςετొ࿥ͯ͠Δ΍Γํͱ΋ҧ͏

Slide 16

Slide 16 text

XCTest Quick ϑΣʔζ1. Xcode͸XCTestCaseΛܧঝͨ͠Πϯελϯε͔ΒdefaultTestSuiteΛ࣮ߦ͢Δ ϑΣʔζ1_1. defaultTestSuite͔ΒgatherExamplesNeeded()͕ݺͼग़͞ΕΔ ϑΣʔζ1_2. gatherExamplesNeeded()͸spec()Λ࣮ߦ ϑΣʔζ1_3. spec()ʹ͋ΔbeforeEach()/it()ΛWorldʹappend͍ͯ͘͠ ϑΣʔζ2. Xcode͸XCTestCaseܧঝ͍ͯ͠ΔΠϯελϯε͔ΒtestInvocationsΛ࣮ߦ͢Δ ϑΣʔζ2_1.testInvocations͸Worldʹappend͞ΕͯΔ΋ͷ͔ΒऔΓग़͠itΛςετͱ࣮ͯ͠ߦ beforeEach/it͸४උϑΣʔζͰอ࣋͞Ε ࣮ߦϑΣʔζͰ࣮ߦ͞ΕΔ

Slide 17

Slide 17 text

͓·͚: ৗʹࣦഊ͢Δྫ 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 } }

Slide 18

Slide 18 text

ྫ: RxSwiftͰεέδϡʔϥΛDIͤͣςετͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • MainScheduler͸ಉظతʹ஋Λྲྀ͢ͱ͖΋͋Δ͠ඇಉظతʹ஋Λྲྀ ͢͜ͱ΋͋Δ • Ͳ͏ղܾ͢Δͷ͔ • εέδϡʔϥΛDI͠ςετεέδϡʔϥΛ࢖͏ • RxSwiftͷίʔυΛಡΉ͔RxSwiftݚڀಡຊΛങ͏ ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ଍

Slide 19

Slide 19 text

ݪҼ3: ςετέʔεͷ࣮ߦॱংґଘ • ྫ • ςετର৅Λෳ਺ςετέʔεͰ࢖͍ճ͠ϓϩύςΟΛηοτ

Slide 20

Slide 20 text

ྫ: ςετର৅Λෳ਺ςετέʔεͰ࢖͍ճ͠ϓϩύςΟΛηοτ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ςετର৅΍Test Doubleʹ࢖͏ΦϒδΣΫτΛෳ਺ςετͰ࢖͍ ճͯ͠͠·͏ͱͦͷϓϩύςΟΛηοτ͠๨ΕͨΓϦηοτ͠๨Ε Δ • Ͳ͏ղܾ͢Δͷ͔ • ෳ਺ςετέʔεͰ࢖͍·Θ͞ͳ͍ ෆ҆ఆͳݪҼ:ςετέʔεͷ࣮ߦॱংґଘ

Slide 21

Slide 21 text

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͕࣮ߦ͞Ε Δͱ…?

Slide 22

Slide 22 text

Quick ͕ѱ͍Θ͚͡Όͳ͘ɺςετର৅΍Өڹ Λٴ΅͢ΦϒδΣΫτ͕ςετ֎͔ΒӨڹΛड ͚Δ͜ͱΛՄೳʹͯ͠͠·͍ͬͯΕ͹ɺςετ ݁Ռ͸ҙਤͤͣෆ҆ఆʹͳΓ΍͍͢ɻ

Slide 23

Slide 23 text

ͨͩͪΐͬͱ͜Εʹؔͯ͠͸QuickΛ஌ͬͯͳ ͍ͱ͍͚ͳ͍͜ͱ͕ଟ͍͔ͳͱࢥ͏

Slide 24

Slide 24 text

ઌड़ͷ௨Γɺ QuickͰ͸beforeEach͸४උϑΣʔζͰ͸ͳ࣮͘ߦϑΣʔζͰ͋ Γɺม਺ͷॳظԽ΍Β࠶ઃఆʢArrangeʣͰ࣮֬ʹ࢖Θ͍ͤͨΜ ͚ͩͲɺbeforeEach͸ΫϩʔδϟͳͷͰArrangeͷνΣοΫΛ͢ ΔΑ͏ͳػೳ͸ͳ͍ɻ

Slide 25

Slide 25 text

ܕͷػೳΛར༻ͯ͠ܕ҆৺ͳςετͷArrange͕Ͱ͖Ε͹΋ͬͱ ྑ͍ͱࢥ͑Δ…ɻ XCTestCaseࣗମͰ΋ؤுΕ͹Ͱ͖Δɻ apple/swift-testing࢖ͬͨΒ͞Βʹදݱྗߴ͘Ͱ͖ͦ͏…ɻ

Slide 26

Slide 26 text

ݪҼ4: ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍ • ྫ • ϝΠϯλʔήοτͰͷςετ͸ϗετΞϓϦέʔγϣϯ͕ىಈͯ͠ ͠·͏ • XCTestCase.waitϝιουʹΑΓεϨου͕σουϩοΫ͢Δͱ͖ ͕͋Δ

Slide 27

Slide 27 text

ྫ: ϝΠϯλʔήοτͰͷςετ͸ϗετΞϓϦέʔγϣϯ͕ىಈͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ઃఆͱͯ͠ɺςετϞδϡʔϧΛϗετΞϓϦຊମ΁ͱࢦఆ͢Δͱςετ࣌ʹΞϓϦ͕ ىಈ͠ɺͦ͜Ͱ෭࡞༻Λ࣮ߦ͠ςετʹӨڹΛ༩͑Δ͜ͱ͕͋Δ • Ͳ͏ղܾ͢Δͷ͔ • AppDelegateΛMockͯ͠Կ΋͠ͳ͍ʢor Mockͤͣݕ஌͠෼ذͯ͠Կ΋͠ͳ͍ʣ • ϗετΞϓϦͷϞδϡʔϧ͸SwiftUI.App΍AppDelegateͷΈ࣋ͪɺͦΕҎ֎ͷॲཧ ͸Ϟδϡʔϧͱ͠෼ׂɺͦΕʹରͯ͠ςετλʔήοτϞδϡʔϧΛ࡞Δ • XcodeઃఆͰHost Application = Noneʹͯ͠ςετ࣮ߦͰ͖Ε͹͍͍ ෆ҆ఆͳݪҼ:ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍

Slide 28

Slide 28 text

ϝΠϯλʔήοτ ϝΠϯλʔήοτͷ ςετλʔήοτ )PTU"QQMJDBUJPOϝΠϯλʔήοτ ςετ࣮ߦͰ)PTU"QQMJDBUJPO͋ΔΜͰ ΞϓϦέʔγϣϯ͕ىಈ࣮ߦ͢Δɻ JNQPSU 1BDLBHFͷ ςετλʔήοτ λʔήοτ JNQPSU 1BDLBHFTXJGU JNQPSU YDXPSLTQBDF ิ଍YDPEFCVJMEͰͷςετͰ͋ΓTXJGUUFTU࣮ߦͰͷςετʹ͍ͭͯͷ࿩Ͱ͸͋Γ·ͤΜ &NCFEEFE'SBNFXPSL λʔήοτ &NCFEEFE.PEVMFͷ ςετλʔήοτ )PTU"QQMJDBUJPO/POF ςετ࣮ߦͰ)PTU"QQMJDBUJPO͕ͳ͍ͳΒɺ ΞϓϦέʔγϣϯ͸ىಈ࣮ߦ͠ͳ͍ɻ JNQPSU

Slide 29

Slide 29 text

ྫ: XCTestCase.waitϝιουʹΑΓεϨου͕σουϩοΫ͢Δͱ͖͕͋Δ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • wait Ͱ Task { @MainActor in } ͷ݁ՌΛ଴ͭςετͳ৔߹ɺwait͸Ϗδʔ΢ΣΠτ͞ ͤͯϝΠϯεϨουΛࢭΊ͍ͯΔͨΊɺTaskͷϝΠϯεϨου࣮ߦΛ્֐͢Δ଴ͪ ͔ͨͱͳΓσουϩοΫ • Ͳ͏ղܾ͢Δͷ͔ • ͦ΋ͦ΋Xcode 14.3ܥͰ͸ܯࠂ͞ΕΔ • Swift ConcurrencyΛ࢖͏৔߹ fulfillment(of:timeout:…) ϝιου͕༻ҙ͞Ε͍ͯΔ ෆ҆ఆͳݪҼ:ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍

Slide 30

Slide 30 text

XCTest.framwork ͷίʔυ͸GitHubͰެ։͞Ε͍ͯΔͷͰಡΊ͹Θ͔Δ͸ͣ

Slide 31

Slide 31 text

͓ΘΓʹ

Slide 32

Slide 32 text

͜ͷൃදͰ ؒҧ͍͕͋ͬͨΓ ҙݟ͕͋ͬͨΒͰ͖Δ͚ͩͳΔ΂͘ Θ͔Γ΍͘͢ࢦఠ࣭໰ͯ͠΋Β͑Δͱ ༗ҙٛͳ΍ΓͱΓ͕Ͱ͖Δ͸ͣͰ͢

Slide 33

Slide 33 text

׬