Upgrade to Pro — share decks privately, control downloads, hide ads and more …

不安定なテストは200種類あんねん

Avatar for yimajo yimajo
October 27, 2023

 不安定なテストは200種類あんねん

Avatar for yimajo

yimajo

October 27, 2023
Tweet

More Decks by yimajo

Other Decks in Programming

Transcript

  1. ݪҼͷ෼ྨ • େ෼ྨ1: ςετίʔυ·ͨ͸ςετର৅ͷϓϩμΫγϣϯίʔυ͕ѱ͍ • ݪҼ1: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ • ݪҼ2: OSSϑϨʔϜϫʔΫཧղෆ଍

    • ݪҼ3: ςετέʔεͷ࣮ߦॱংґଘ • ݪҼ4: ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍ • ݪҼ ͦͷଞ • େ෼ྨ2: ςετ࣮ߦϚγϯཁҼʢ؀ڥʣ ࠓ೔࿩͢͜ͱ
  2. ྫ: Foundation.Date.init() / Foundation.Date.now • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ݻఆ஋Ͱ͸ͳ͍ͨΊ • ݱࡏ࣌ࠁͷ༻ҙ͔Βར༻͢Δ·Ͱ૝ఆ֎ʹ͕࣌ؒܦա͢Δ

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

    • Swift Standard LibraryͷContinuousClock • ੔਺ͳͲͷཚ਺ੜ੒ ෆ҆ఆͳݪҼ: ࣮ߦ࣌ʹܾఆ͢Δಈతͳ஋ʹΑΔςετ࣮ߦ https://github.com/pointfreeco/swift-dependencies/tree/main/ Sources/Dependencies/DependencyValues ࢀߟ: pointfreeco/swift-dependencies
  4. 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 ݁Ռ
  5. XcodeͰͷςετ࣮ߦ (xcodebuild test ܥ) ͸ ϑΣʔζͱͯ͠ ςετͷ ొ࿥ ͱ ࣮ߦ

    ͷ2ϑΣʔζʹ ෼͔Ε͍ͯͯ Quick ͸ͦΕΛར༻͍ͯ͠Δɻ ςετొ࿥ϑΣʔζ ςετ࣮ߦϑΣʔζ XCTestCaseͷdefaultTestSuite XCTestCaseͷtestInvocations ิ଍BQQMFTXJGUUFTUJOHͰݱঢ়ςετొ࿥ͯ͠Δ΍Γํͱ΋ҧ͏
  6. 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͸४උϑΣʔζͰอ࣋͞Ε ࣮ߦϑΣʔζͰ࣮ߦ͞ΕΔ
  7. ͓·͚: ৗʹࣦഊ͢Δྫ 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 } }
  8. ྫ: RxSwiftͰεέδϡʔϥΛDIͤͣςετͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • MainScheduler͸ಉظతʹ஋Λྲྀ͢ͱ͖΋͋Δ͠ඇಉظతʹ஋Λྲྀ ͢͜ͱ΋͋Δ • Ͳ͏ղܾ͢Δͷ͔ •

    εέδϡʔϥΛDI͠ςετεέδϡʔϥΛ࢖͏ • RxSwiftͷίʔυΛಡΉ͔RxSwiftݚڀಡຊΛങ͏ ෆ҆ఆͳݪҼ:OSSϑϨʔϜϫʔΫཧղෆ଍
  9. 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͕࣮ߦ͞Ε Δͱ…?
  10. ྫ: ϝΠϯλʔήοτͰͷςετ͸ϗετΞϓϦέʔγϣϯ͕ىಈͯ͠͠·͏ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • ઃఆͱͯ͠ɺςετϞδϡʔϧΛϗετΞϓϦຊମ΁ͱࢦఆ͢Δͱςετ࣌ʹΞϓϦ͕ ىಈ͠ɺͦ͜Ͱ෭࡞༻Λ࣮ߦ͠ςετʹӨڹΛ༩͑Δ͜ͱ͕͋Δ • Ͳ͏ղܾ͢Δͷ͔ •

    AppDelegateΛMockͯ͠Կ΋͠ͳ͍ʢor Mockͤͣݕ஌͠෼ذͯ͠Կ΋͠ͳ͍ʣ • ϗετΞϓϦͷϞδϡʔϧ͸SwiftUI.App΍AppDelegateͷΈ࣋ͪɺͦΕҎ֎ͷॲཧ ͸Ϟδϡʔϧͱ͠෼ׂɺͦΕʹରͯ͠ςετλʔήοτϞδϡʔϧΛ࡞Δ • XcodeઃఆͰHost Application = Noneʹͯ͠ςετ࣮ߦͰ͖Ε͹͍͍ ෆ҆ఆͳݪҼ:ϓϩάϥϛϯάݴޠ/SDKͷཧղෆ଍
  11. ϝΠϯλʔήοτ ϝΠϯλʔήοτͷ ςετλʔήοτ )PTU"QQMJDBUJPOϝΠϯλʔήοτ ςετ࣮ߦͰ)PTU"QQMJDBUJPO͋ΔΜͰ ΞϓϦέʔγϣϯ͕ىಈ࣮ߦ͢Δɻ JNQPSU 1BDLBHFͷ ςετλʔήοτ λʔήοτ

    JNQPSU 1BDLBHFTXJGU JNQPSU YDXPSLTQBDF ิ଍YDPEFCVJMEͰͷςετͰ͋ΓTXJGUUFTU࣮ߦͰͷςετʹ͍ͭͯͷ࿩Ͱ͸͋Γ·ͤΜ &NCFEEFE'SBNFXPSL λʔήοτ &NCFEEFE.PEVMFͷ ςετλʔήοτ )PTU"QQMJDBUJPO/POF ςετ࣮ߦͰ)PTU"QQMJDBUJPO͕ͳ͍ͳΒɺ ΞϓϦέʔγϣϯ͸ىಈ࣮ߦ͠ͳ͍ɻ JNQPSU
  12. ྫ: XCTestCase.waitϝιουʹΑΓεϨου͕σουϩοΫ͢Δͱ͖͕͋Δ • ͳͥෆ҆ఆ͞ʹͭͳ͕Δͷ͔ • wait Ͱ Task { @MainActor

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