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

SwiftにおけるMockライブラリの活用/swift-mock-library

 SwiftにおけるMockライブラリの活用/swift-mock-library

iOS Test Night #7 での発表.
https://testnight.connpass.com/event/79163/

Avatar for Yusuke Hosonuma

Yusuke Hosonuma

March 27, 2018
Tweet

More Decks by Yusuke Hosonuma

Other Decks in Programming

Transcript

  1. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. iOS Test Night

    #7 2018/03/26 (Mon) 
 ࡉপ ༞հ@DeNA 4XJGUʹ͓͚Δ .PDLϥΠϒϥϦͷ׆༻ 1
  2. ˙:VTVLF)PTPOVNBʢ!UPCJʣ • ॴଐ ⁃ %F/"ɹ48&5άϧʔϓɹςετج൫νʔϜ ⁃ ςετٕज़ͷௐࠪɺࣾ಺πʔϧ։ൃ • 'BWPSJUF ⁃

     • ۙگ ⁃ USZ4XJGU"GUFS5BMLTEBZͰൃදʢ4XJGU1.Ͱ࡞Δ$-*ʣ ⁃ ,PUMJOΛ৮͚ͬͯͨͲɺ4XJGUͷྑ͞ʹ΋࠶ͼؾ͖ͮ࢝ΊΔ ⁃ 4XJGUͷ.PDLϥΠϒϥϦʹՄೳੑΛײ͡Δɹˡ͍·͜͜ 8IP Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 2
  3. ΞδΣϯμ 5 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLͱ͸ • 4XJGUʹ͓͚Δ.PDLࣄ৘ • .PDLΛࣗ෼Ͱ࡞Δ • 044ϥΠϒϥϦͷ঺հ • ϥΠϒίʔσΟϯάʢ࣌ؒ͋Ε͹ʂʣ • ·ͱΊ
  4. Mockͱ͸ʁ 7 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ຊ෺Ͱ͸ͳِ͍෺ͷΦϒδΣΫτʢςετμϒϧͱ΋ʣ • ୯ମςετ΍ಈ࡞֬ೝͰར༻ • ྫ • "1*͕ະ׬੒
 ˠμϛʔϨεϙϯεΛฦ͢.PDL • ґଘؔ܎͕ෳࡶͳςετ
 ˠґଘΦϒδΣΫτΛ.PDLʹมߋ
  5. Mockͷར༻ྫ 8 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Waiter

    CockProtocol RealCock ΢ΣΠλʔ ྉཧਓ1SPUPDPM ྉཧਓ
  6. Mockͷར༻ྫ 9 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Waiter

    CockProtocol RealCock ୯ମςετ͍ͨ͠ʜ ͚Ͳ࣮૷Ͱ͖ͯͳ͍ʜ
  7. Mockͷར༻ྫ 10 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Waiter

    CockProtocol MockCock ςετ༻ͷِΦϒδΣΫτ
  8. MockͰԿ͕Ͱ͖Δʁ 11 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ͋Δ"1*ݺͼग़࣌͠ʹɺ೚ҙͷ஋Λฦ͢ • ಈ࡞֬ೝ༻ͷ"1*Ϩεϙϯε • ྫ֎తͳΤϥʔ • ݺͼग़݁͠Ռͷ֬ೝ • ͋Δϝιου"͕ݺͼग़͞Ε͔ͨ • ʻճ਺ʼ͸ਖ਼͍͔͠ʁ • ʻҾ਺ʼ͸ਖ਼͍͔͠ʁ
  9. ͳͥMockΛ࢖͏͔ʁ 12 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ࣮ΦϒδΣΫτ͕ଘࡏ͠ͳ͍ • ࣮૷த • ࣮ΦϒδΣΫτΛར༻͢Δͱ͕͔͔࣌ؒΔ • ௨৴࣌ؒ • σʔλϕʔε΁ͷΞΫηε • ґଘؔ܎Λ੾Γ཭͍ͨ͠৔߹ • ୯ମςετ
  10. ͜͜·Ͱ 13 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLʹِ෺ͷΦϒδΣΫτ • Կ͕Ͱ͖Δʁ • ೚ҙͷ஋Λฦ͢ • ݺͼग़݁͠Ռͷ֬ೝ • ͳͥར༻͢Δʁ • ࣮ΦϒδΣΫτ͕ଘࡏ͠ͳ͍ • ࣮ΦϒδΣΫτͩͱ͕͔͔࣌ؒΔ • ୯ମςετ UIFO3FUVSO 7FSJGZ
  11. Objective-C ࣌୅ 16 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    • 0CKFDUJWF$ • ಈతϥϯλΠϜʢ0CKFDUJWF$3VOUJNFʣ • .FUIPE4XJ[[MJOH • .FUIPE.JTTJOH ɹɹˠϝλϓϩάϥϛϯάʢࠇຐज़ʣͷ׆༻ • 0$.PDL • 0CKFDUJWF$ʹ͓͚ΔσϑΝΫτϥΠϒϥϦ • ݴޠϥϯλΠϜΛϑϧ׆༻
  12. Swift ࣌୅ɹংষ 18 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    • 4XJGU • ੩తϥϯλΠϜ • ϦϑϨΫγϣϯ"1*ʢಡΈऔΓઐ༻ʣ • 0CKFDUJWF$ϥϯλΠϜͷ׆༻͸ݶఆత
 ˠϝλϓϩάϥϛϯάʢࠇຐज़ʣͷ׆༻ • 0$.PDL • ݴޠϒϦοδͰ࢖༻Ͱ͖Δʢͦͷ༐ؾ͕͋Ε͹ʣ • 0$.PDL͕4XJGUΛ׬શαϙʔτ͢Δ͜ͱ͸ͳ͍ ެࣜ'"2ΑΓҙ༁
  13. Swift ࣌୅ɹͦΕ͔Β… 19 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    • ॳظͷΞϓϩʔν • .PDL͸खಈ࡞੒ • 3FUVSO7FSJGZΛαϙʔτ͢Δ044 • 4XJGU.PDLɹ⭐ • .PDL'JWFɹ⭐ • %PCCZɹ⭐ ɹˠ͍ͣΕ΋4XJGUYͰϝϯς͕ࢭ·Δ
  14. Swift ࣌୅ɹͦͯ͠… 20 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    • 88%$ • 1SPUPDPM0SJFOUFE1SPHSBNNJOH͕ఏএ
 ˠ͞Βʹ.PDL͕ॏཁʹʜʁ • ৽͍͠Ξϓϩʔνొ৔ʂ • $VDLPP • .PDLΛࣗಈੜ੒ • .PDLJUP +BWB ΠϯεύΠΞ ɹɹˠ͋ͱͰݟ͍ͯ͘
  15. ϓϩμΫτίʔυ 24 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. protocol

    CockProtocol { func cockRamen(bowls: Int, soup: Soup) -> [Ramen] } enum Soup { case ে༉ case ຯḩ } struct Ramen { var soup: Soup } struct Waiter { let cock: CockProtocol // ґଘΦϒδΣΫτ func order() -> [Ramen] { return cock.cockRamen(bowls: 2, soup: .ে༉) } } ͜ΕΛ.PDLʹ͢Δ
  16. Mockίʔυ 26 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    MockCock: CockProtocol { var cockRamenCallCount: Int = 0 var cockRamenLastBowls: Int = 0 var cockRamenCallReturn: [Ramen] = [] var cockRamenLastSoup: Soup = .ে༉ func cockRamen(bowls: Int, soup: Soup) -> [Ramen] { // ݺͼग़͠ճ਺ͷه࿥ cockRamenCallCount += 1 // Ҿ਺ͷه࿥ cockRamenLastBowls = bowls cockRamenLastSoup = soup // ೚ҙͷ஋Λฦ͢ return cockRamenCallReturn } } ݺͼग़࣌͠ͷ৘ใΛه࿥ ઃఆ͞Εͨ໭Γ஋Λฦ͢
  17. ୯ମςετίʔυ 28 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } }
  18. ୯ମςετίʔυ 29 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } } ᶃDPDL3BNFO ͕ݺ͹Εͨ࣌ʹ ͜ͷ஋Λฦ͢Α͏ʹઃఆ
  19. ୯ମςετίʔυ 30 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } } ᶄPSEFS ͷݺͼग़݁͠Ռʹ͍ͭͯ ظ଴ͨ݁͠Ռ͔ݕূ
  20. ୯ମςετίʔυ 31 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } } ᶅ$PDLΦϒδΣΫτͷϝιου͕ ҙਤͨ͠௨Γʹݺͼग़͞Ε͔ͨݕূ
  21. ͜Ε͘Β͍ͳΒଥڠ͢Δʁ 33 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    MockCock: CockProtocol { var cockRamenCallCount: Int = 0 var cockRamenLastBowls: Int = 0 var cockRamenCallReturn: [Ramen] = [] var cockRamenLastSoup: Soup = .ে༉ func cockRamen(bowls: Int, soup: Soup) -> [Ramen] { cockRamenCallCount += 1 cockRamenLastBowls = bowls cockRamenLastSoup = soup return cockRamenCallReturn } } class WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } }
  22. ͜Ε͘Β͍ͳΒଥڠ͢Δʁ 34 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    MockCock: CockProtocol { var cockRamenCallCount: Int = 0 var cockRamenLastBowls: Int = 0 var cockRamenCallReturn: [Ramen] = [] var cockRamenLastSoup: Soup = .ে༉ func cockRamen(bowls: Int, soup: Soup) -> [Ramen] { cockRamenCallCount += 1 cockRamenLastBowls = bowls cockRamenLastSoup = soup return cockRamenCallReturn } } class WaiterTests: XCTestCase { func test_order() { let mock = MockCock() mock.cockRamenCallReturn = [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)] let results = Waiter(cock: mock).order() XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) XCTAssertEqual(mock.cockRamenCallCount, 1) XCTAssertEqual(mock.cockRamenLastBowls, 2) XCTAssertEqual(mock.cockRamenLastSoup, .ে༉) } } ྫྷ੩ʹߟ͑Δͱ… ɾ1 Protocol ɾ1 Method ͦΕͳͷʹ͜ͷίʔυྔʁ
  23. ࣗ࡞Mockͷײ૝ 36 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ࣗ࡞.PDL • ࡞Δͷࣗମ͸೉͘͠ͳ͍ • ͨͩϘΠϥʔϓϨʔτ͕ଟ͍PS[ • ࡞Δͷ͕໘౗ͩͱ • .PDLࣗମʹόάΛ࢓ࠐΉ • ςετ͕ࡶʹͳΔ • ςετʹର͢ΔϞνϕʔγϣϯ%PXO ɹˠྑ͘ͳ͍ํ޲ʹߦ͘ͷ͸໨ʹݟ͍͑ͯΔ
  24. Swift ͷ MockϥΠϒϥϦ 38 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. ˒ छผ Swift Ұݴ Cuckoo 711 ࣗಈੜ੒ 4.0 ɾMockitoΠϯεύΠΞʢࣅͯΔʣ
 ɾSourceKittenΛར༻ SwiftyMocky 301 ʏ 4.0 ɾSwiftyͳAPI
 ɾSourceryΛར༻ͯ͠ੜ੒ Mockit 66 αϙʔτܥ 4.0 ɾMockitoΠϯεύΠΞ
 ɾ·ͩൃల్্ʁ Dobby 151 ʏ 2.x ɾࠓޙ΋ϝϯς͞Εͳͦ͏ʁ MockFive 201 ʏ 2.x ʏ SwiftMock 223 ʏ 2.x ʏ
  25. Mockit 40 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    αϒΫϥεԽʹΑΔ.PDLͷαϙʔτ • 1SPUPDPM͸αϙʔτ͍ͯ͠ͳ͍ʁ • .PDLͷ਽ܗ͸ࣗ࡞ • গͳ͍ίʔυྔͰ.PDLΛ࣮ݱ • ՝୊ • Τϥʔ࣌ʹςετίʔυʹϚʔΧʔ͕෇͔ͳ͍ • ·ͩൃల్্ͱ͍͏ʢݸਓͷʣҹ৅ ࠓޙʹظ଴ͯ͠ʢ͈́
  26. Cuckoo 42 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLJUPΠϯεύΠΞ • ͔ͳΓࣅ͍ͯΔҹ৅ • ࣗಈੜ੒ • ϑΝΠϧΛࣗ෼Ͱࢦఆ͢Δඞཁ͋Γ
  27. Cuckoo 43 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = MockCockProtocol() stub(mock) { stub in when(stub.cockRamen(bowls: any(), soup: any())) .thenReturn([Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)]) } // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) verify(mock).cockRamen(bowls: equal(to: 2), soup: equal(to: .ে༉)) } ࣗಈੜ੒͞Εͨ.PDL
  28. Cuckoo 44 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = MockCockProtocol() stub(mock) { stub in when(stub.cockRamen(bowls: any(), soup: any())) .thenReturn([Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)]) } // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) verify(mock).cockRamen(bowls: equal(to: 2), soup: equal(to: .ে༉)) } DPDL3BNFO ͕ݺͼग़͞Εͨ࣌ͷ μϛʔͷ໭Γ஋Λઃఆ DPDL3BNFO ͷݺͼग़͠Ҿ਺͕ ҙਤͨ͠΋ͷ͔ݕূʢWFSJGZʣ
  29. Cuckoo 45 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = MockCockProtocol() stub(mock) { stub in when(stub.cockRamen(bowls: any(), soup: any())) .thenReturn([Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)]) } // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) verify(mock).cockRamen(bowls: equal(to: 2), soup: equal(to: .ে༉)) } .PDLJUPϥΠΫͳ"1* .BUDIFSΛ࠾༻
  30. SwiftyMocky 47 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLJUPϥΠΫ • ߟ͑ํ͸ࣅ͍ͯΔ • 4XJGUZͳ"1* • ίʔυิ׬͕ޮ͖΍͍͢"1*ઃܭ • ࣗಈੜ੒ • NPDLZZNM͔Βੜ੒ • ϑΝΠϧ؂ࢹΛαϙʔτ • 4PVSDFSZΛ಺෦తʹར༻
  31. SwiftyMocky 48 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = CockProtocolMock() mock.given(.cockRamen(bowls: .any, soup: .any, willReturn: [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)])) // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) mock.verify(.cockRamen(bowls: .value(2), soup: .value(.ে༉))) } } ࣗಈੜ੒͞Εͨ.PDL
  32. SwiftyMocky 49 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = CockProtocolMock() mock.given(.cockRamen(bowls: .any, soup: .any, willReturn: [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)])) // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) mock.verify(.cockRamen(bowls: .value(2), soup: .value(.ে༉))) } } DPDL3BNFO ͕ݺͼग़͞Εͨ࣌ͷ μϛʔͷ໭Γ஋Λઃఆ DPDL3BNFO ͷݺͼग़͠Ҿ਺͕ ҙਤͨ͠΋ͷ͔ݕূʢWFSJGZʣ
  33. SwiftyMocky 50 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    WaiterTests: XCTestCase { func test_order() { // ४උ let mock = CockProtocolMock() mock.given(.cockRamen(bowls: .any, soup: .any, willReturn: [Ramen(soup: .ে༉), Ramen(soup: .ຯḩ)])) // ݺͼग़͠ let results = Waiter(cock: mock).order() // ݕূ XCTAssertEqual(results.count, 2) XCTAssertTrue(results.contains { $0.soup == .ে༉ }) XCTAssertTrue(results.contains { $0.soup == .ຯḩ }) mock.verify(.cockRamen(bowls: .value(2), soup: .value(.ে༉))) } } ิ׬͠΍͍͢ ิ׬͠΍͍͢
  34. ·ͱΊ 53 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDL • ୯ମςετͳͲͰ࢖͑Δِ෺ͷΦϒδΣΫτ • ͢΂ͯࣗ࡞͢Δͷ͸ίετ • 4XJGU • ಈతϥϯλΠϜΛར༻ͨ͠.PDL͸೉͍͠ • खಈPSίʔυੜ੒ʹͳΔ • 044 • ίʔυੜ੒͕ओྲྀʹͳΓͦ͏ʁʁ