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/

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 • ίʔυੜ੒͕ओྲྀʹͳΓͦ͏ʁʁ