HTTPモックライブラリ「Mockingjay」を使ってみた話/swift-mockingjay

 HTTPモックライブラリ「Mockingjay」を使ってみた話/swift-mockingjay

iOS Test Night #8 での発表資料です。
https://testnight.connpass.com/event/90959/

70d9714ea13fc1133803d61fb16e4160?s=128

Yusuke Hosonuma

July 24, 2018
Tweet

Transcript

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

    #8 2018/07/24 (Tue) 
 ࡉপ ༞հ@DeNA )5514UVCϥΠϒϥϦ ʮ.PDLJOHKBZʯΛ࢖ͬͯΈͨ࿩ 1
  2. ˙:VTVLF)PTPOVNBʢ!UPCJʣ • ॴଐ ⁃ %F/"ɹ48&5άϧʔϓɹςετج൫νʔϜ • 'BWPSJUF ⁃  •

    ۙگ ⁃ ,VCFSOFUFT(,&ָ͕͍͠ʂ ⁃ J04%$ͰϨΪϡϥʔτʔΫʢ෼ʣʹ࠾୒ ࣗݾ঺հ Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 2
  3. ࠓ೔ɺ࿩͢͜ͱ 3 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  4. )5514UVCϥΠϒϥϦ ʮ.PDLJOHKBZʯ ͷ঺հɾ޻෉ͨ͠ͱ͜Ζ 4 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved.
  5. ΞδΣϯμ 5 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    )5514UVCͱ͸ʁ • ࠓճͷར༻έʔε • .PDLJOHKBZͱ͸ʁ • ޻෉ͨ͠ͱ͜Ζ • ·ͱΊ
  6. )5514UVCͱ͸ʁ 6 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  7. HTTP Stub ͱ͸ʁ 7 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. • )551ϦΫΤετ௨৴ʹର͢Δ4UVCʢِ෺ʣ • ϦΫΤετʹରͯ͠ɺ೚ҙͷϨεϙϯεΛฦ͢ • ֎෦αʔόʹґଘ͠ͳ͍ςετ͕ॻ͚Δ
  8. HTTP௨৴ 8 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ΞϓϦ

    αʔό (&5BQJBSUJDMF 0,
  9. HTTP௨৴ 9 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ΞϓϦ

    αʔό (&5BQJBSUJDMF 0, ʲ՝୊ʳ Τϥʔ͕ฦ٫͞Εͨ৔߹ͷ ςετ͸Ͳ͏΍Δʁ
  10. HTTP௨৴ϨϕϧͷςετΛͲ͏͢Δʁ 10 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ΍Βͳ͍ • ௨৴༻.PEFMΫϥεͷ4UVCͰΧόʔ • &&ςετͰΧόʔ • ΍Δ • αʔόଆͷઃఆΛҰ࣌తʹมߋ • )5514UVC
  11. HTTP௨৴ϨϕϧͷςετΛͲ͏͢Δʁ 11 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    ΍Βͳ͍ • ௨৴༻.PEFMΫϥεͷ4UVCͰΧόʔ • &&ςετͰΧόʔ • ΍Δ • αʔόଆͷઃఆΛҰ࣌తʹมߋ • )5514UVC ࠓճͷબ୒
  12. HTTP Stub 12 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    ΞϓϦ αʔό (&5BQJBSUJDMF /05@'06/% )5514UVC αʔόͱͷؒʹೖͬͯɺ ೚ҙͷϨεϙϯεΛฦ͢ʂ
  13. ࠓճͷར༻έʔε 13 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  14. ࠓճͷར༻έʔε 14 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Client

    αʔό 4XJGU1. αʔόͱԿ౓΋௨৴͢Δ ઃఆ஋ʹج͍ͮͯ$-*Λ࣮ߦͯ͠ɺ ҙਤͨ͠௨৴͕ߦΘΕΔ͔Λݕূ͍ͨ͠ʜ $-*πʔϧ
  15. )5514UVC ࠓճͷར༻έʔε 15 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    Client αʔό 4XJGU1. )5514UVCϥΠϒϥϦΛ࢖ͬͯɺ ΠϯςάϨʔγϣϯʢ݁߹ʣςετ .PDLJOHKBZΛ࢖ͬͯΈͨ
  16. .PDLJOHKBZͱ͸ʁ 16 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  17. Mockingjayͱ͸ʁ 17 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    )5514UVCϥΠϒϥϦ • 4XJGU • ϦΫΤετఆٛʢ.BUDIFSʣ • Ϩεϙϯεੜ੒ʢ#VJMEFSʣ • 63-4FTTJPO • $POpHVSBUJPOΛࠩ͠ସ͑ • 63-4FTTJPOҎ֎ͷ௨৴ʹ͸ར༻Ͱ͖ͳ͍ IUUQTHJUIVCDPNLZMFG.PDLJOHKBZ .FUIPE4XJ[[MJOH
  18. ModelΫϥε 18 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    url = "http://example.com/api" struct ProposalRepository { func all(_ handler: @escaping ([ProposalElement]) -> Void) { Alamofire.request(url).responseProposal { response in if let proposals = response.result.value { handler(proposals) } } } }
  19. ModelΫϥε 19 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    url = "http://example.com/api" struct ProposalRepository { func all(_ handler: @escaping ([ProposalElement]) -> Void) { Alamofire.request(url).responseProposal { response in if let proposals = response.result.value { handler(proposals) } } } } BQJ
  20. ModelΫϥε 20 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    url = "http://example.com/api" struct ProposalRepository { func all(_ handler: @escaping ([ProposalElement]) -> Void) { Alamofire.request(url).responseProposal { response in if let proposals = response.result.value { handler(proposals) } } } } "MBNPpSF
  21. ModelΫϥε 21 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    url = "http://example.com/api" struct ProposalRepository { func all(_ handler: @escaping ([ProposalElement]) -> Void) { Alamofire.request(url).responseProposal { response in if let proposals = response.result.value { handler(proposals) } } } } $BMMCBDL
  22. ModelΫϥε 22 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    url = "http://example.com/api" struct ProposalRepository { func all(_ handler: @escaping ([ProposalElement]) -> Void) { Alamofire.request(url).responseProposal { response in if let proposals = response.result.value { handler(proposals) } } } } $BMMCBDL ͪͳΈʹRVJDLUZQFJPͰίʔυੜ੒
  23. GET /api ʹରͯ͠ɺJSONΛฦ͢ 23 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊", ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊", ], ] stub(http(.get, uri: "/api"), json(data))
  24. GET /api ʹରͯ͠ɺJSONΛฦ͢ 24 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊", ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊", ], ] stub(http(.get, uri: "/api"), json(data)) Ϩεϙϯεσʔλ
  25. GET /api ʹରͯ͠ɺJSONΛฦ͢ 25 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊", ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊", ], ] stub(http(.get, uri: "/api"), json(data)) ॲཧ͢ΔύεΛఆٛ
  26. GET /api ʹରͯ͠ɺJSONΛฦ͢ 26 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊", ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊", ], ] stub(http(.get, uri: "/api"), json(data)) Ϩεϙϯεఆٛ
  27. ࣮ࡍͷςετίʔυ 27 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] stub(http(.get, uri: "/api"), json(data)) let exp = expectation(description: "") repository.all { proposals in XCTAssertEqual(2, proposals.count) XCTAssertEqual("λΠτϧ1", proposals.first?.title) XCTAssertEqual("Ϣʔβ໊", proposals.first?.user) exp.fulfill() } wait(for: [exp], timeout: 3)
  28. ࣮ࡍͷςετίʔυ 28 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] stub(http(.get, uri: "/api"), json(data)) let exp = expectation(description: "") repository.all { proposals in XCTAssertEqual(2, proposals.count) XCTAssertEqual("λΠτϧ1", proposals.first?.title) XCTAssertEqual("Ϣʔβ໊", proposals.first?.user) exp.fulfill() } wait(for: [exp], timeout: 3) )5514UVCઃఆ
  29. ࣮ࡍͷςετίʔυ 29 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] stub(http(.get, uri: "/api"), json(data)) let exp = expectation(description: "") repository.all { proposals in XCTAssertEqual(2, proposals.count) XCTAssertEqual("λΠτϧ1", proposals.first?.title) XCTAssertEqual("Ϣʔβ໊", proposals.first?.user) exp.fulfill() } wait(for: [exp], timeout: 3) .PEFMͷςετ
  30. ࣮ࡍͷςετίʔυ 30 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. let

    data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] stub(http(.get, uri: "/api"), json(data)) let exp = expectation(description: "") repository.all { proposals in XCTAssertEqual(2, proposals.count) XCTAssertEqual("λΠτϧ1", proposals.first?.title) XCTAssertEqual("Ϣʔβ໊", proposals.first?.user) exp.fulfill() } wait(for: [exp], timeout: 3) ඇಉظॲཧΛ଴ͭ
  31. ޻෉ͨ͠ͱ͜Ζ 31 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  32. ᶃγϯλοΫεϊΠζ 32 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  33. Mockingjay API 33 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    stub(http(.get, uri: "/api")) { request in let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] return jsonBody(data)(request) }
  34. Mockingjay API 34 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    stub(http(.get, uri: "/api")) { request in let data: [[String: String]] = [ [ "title": "λΠτϧ1", "user": "Ϣʔβ໊" ], [ "title": "λΠτϧ2", "user": "Ϣʔβ໊" ], ] return jsonBody(data)(request) } ͕ଟͯ͘গ͠ಡΈͮΒ͍ʜ • ϊΠζײ͕͋Δ • .BUDIFS"1*͸ίʔυิ׬ͮ͠Β͍
  35. ϥούʔAPI Λॻ͍ͯΈΔ 35 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    func stubHttp(_ method: HTTPMethod, _ path: String, _ builder: @escaping Builder) { stub(http(method, uri: path)) { request in builder(request) } } ຊ౰ʹϥοϓ͚ͨͩ͠
  36. Before / After 36 Copyright (C) DeNA Co.,Ltd. All Rights

    Reserved. // // Before: // stub(http(.get, uri: "/api") { } // // After // stubHttp(.get, "/api") { } • ࢹೝੑ͕Α͘ͳͬͨʂ • ֮͑Δ͜ͱ΋গͳ͘ɺิ׬΋͠΍͍͢ʂ
  37. ᶄ4UVC͕ ݺͼग़͞Εͨ͜ͱΛอূ 37 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  38. ૺ۰ͨ͠ࣄ৅ 38 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 

    TUVCΛઃఆ  ςετΛॻ͘  ੒ޭͯ͠ظ଴Ͳ͓Γಈ͍ͯΔͱࢥͬͨ  ࣮ࡍʹ͸63-ͷύε͕ҟͳ͓ͬͯΓ
 ݺ͹Ε͍ͯͳ͔ͬͨPS[ ͜͏͍ͬͨϛεΛແ͍ͨ͘͠ɾɾɾ
  39. Stub ݺͼग़͠Λอূ͢Δ 39 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    let exp = expectation(description: “/api") stubHttp(.get, "/api") { request in exp.fulfill() let data: [[String: String]] = [] return jsonBody(data)(request) } wait(for: [exp], timeout: 3)
  40. Stub ݺͼग़͠Λอূ͢Δ 40 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    let exp = expectation(description: “/api") stubHttp(.get, "/api") { request in exp.fulfill() let data: [[String: String]] = [] return jsonBody(data)(request) } wait(for: [exp], timeout: 3) 9$5FTU&YQFDUBUJPOΛੜ੒
  41. Stub ݺͼग़͠Λอূ͢Δ 41 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    let exp = expectation(description: “/api") stubHttp(.get, "/api") { request in exp.fulfill() let data: [[String: String]] = [] return jsonBody(data)(request) } wait(for: [exp], timeout: 3) 4UVC͕ݺͼग़͞ΕͨΒGVMMpMM
  42. Stub ݺͼग़͠Λอূ͢Δ 42 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    let exp = expectation(description: “/api") stubHttp(.get, "/api") { request in exp.fulfill() let data: [[String: String]] = [] return jsonBody(data)(request) } wait(for: [exp], timeout: 3) GVMMpMM͞Εͯͳ͚Ε͹ λΠϜΞ΢τͰࣦഊ
  43. Stub ݺͼग़͠Λอূ͢Δ 43 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    let exp = expectation(description: “/api") stubHttp(.get, "/api") { request in exp.fulfill() let data: [[String: String]] = [] return jsonBody(data)(request) } wait(for: [exp], timeout: 3) • TUVC͕ݺͼग़͞Εͳ͍৔߹͸Τϥʔʹʂ • Ͱ΋ɺ৑௕ͳίʔυ͕ଟ͍ʁˠ͜Ε͸࣍Ͱʂ
  44. ᶅ%4-ͷ੔උ 44 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  45. ݱঢ়ͷ՝୊ 45 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    TUVC͕ݺͼग़͞ΕΔ͜ͱΛอূͰ͖ͨ • ຖճ͜ΕΛॻ͘ͷ͸໘౗ • ຊ࣭తͰͳ͍ίʔυ͕ଟ͘ͳΔ໰୊΋
  46. ݱঢ়ͷ՝୊ 46 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    TUVC͕ݺͼग़͞ΕΔ͜ͱΛอূͰ͖ͨ • ຖճ͜ΕΛॻ͘ͷ͸໘౗ • ຊ࣭తͰͳ͍ίʔυ͕ଟ͘ͳΔ໰୊΋ ΋ͬͱָΛ͍ͨ͠ʂ
  47. ࠷ऴతͳίʔυ 47 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. expectCall(

    stubHttp(.get, “/api/v1“) { request in ... } ) expectCall( stubHttp(.get, “/api/v2“) { request in ... } ) waitCallExpectation()
  48. stubHttp ϝιουͷ֦ு 48 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    func stubHttp(_ method: HTTPMethod, _ path: String, _ builder: @escaping Builder) -> XCTestExpectation { let exp = expectation(description: "request \(method): \(path)") stub(http(method, uri: path)) { request in exp.fulfill() return builder(request) } return exp }
  49. stubHttp ϝιουͷ֦ு 49 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    func stubHttp(_ method: HTTPMethod, _ path: String, _ builder: @escaping Builder) -> XCTestExpectation { let exp = expectation(description: "request \(method): \(path)") stub(http(method, uri: path)) { request in exp.fulfill() return builder(request) } return exp } ಺෦Ͱ&YQFDUBUJPOΛੜ੒
  50. stubHttp ϝιουͷ֦ு 50 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    func stubHttp(_ method: HTTPMethod, _ path: String, _ builder: @escaping Builder) -> XCTestExpectation { let exp = expectation(description: "request \(method): \(path)") stub(http(method, uri: path)) { request in exp.fulfill() return builder(request) } return exp } TUVC͕ݺͼग़͞ΕͨΒGVMMpMM
  51. stubHttp ϝιουͷ֦ு 51 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    func stubHttp(_ method: HTTPMethod, _ path: String, _ builder: @escaping Builder) -> XCTestExpectation { let exp = expectation(description: "request \(method): \(path)") stub(http(method, uri: path)) { request in exp.fulfill() return builder(request) } return exp } &YQFDUBUJPOΛSFUVSOͰฦ͢
  52. ਌ͷςετΫϥεΛ࡞੒ 52 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } }
  53. ਌ͷςετΫϥεΛ࡞੒ 53 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } 9$5FTU&YQFDUBUJPOͷ഑ྻΛ༻ҙ
  54. ਌ͷςετΫϥεΛ࡞੒ 54 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } Ҿ਺ʹ౉͞Εͨ&YQFDUBUJPOΛ௥Ճ
  55. ਌ͷςετΫϥεΛ࡞੒ 55 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } ௥Ճ͞Εͨ&YQFDUBUJPOΛXBJU
  56. શମ 56 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } // ςετίʔυ expectCall( stubHttp(.get, “/api/v1“) { request in ... } ) waitCallExpectation()
  57. શମ 57 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } // ςετίʔυ expectCall( stubHttp(.get, “/api/v1“) { request in ... } ) waitCallExpectation() ฦ٫͞Εͨ&YQFDUBUJPO͕Ҿ਺ʹ౉Δ
  58. શମ 58 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } // ςετίʔυ expectCall( stubHttp(.get, “/api/v1“) { request in ... } ) waitCallExpectation() ௥Ճ͞Εͨ&YQFDUBUJPOΛXBJU
  59. શମ 59 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. class

    HttpTestCase: XCTestCase { private var stubHttpCallExpectations: [XCTestExpectation]! } extension HttpTestCase { func expectCall(_ exp: XCTestExpectation) { stubHttpCallExpectations.append(exp) } func waitCallExpectation() { wait(for: stubHttpCallExpectations, timeout: 3) } } // ςετίʔυ expectCall( stubHttp(.get, “/api/v1“) { request in ... } ) waitCallExpectation()
  60. ·ͱΊ 60 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  61. ·ͱΊ 61 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLJOHKBZ͸4XJGUͷ)5514UVCϥΠϒϥϦ • )551௨৴ͷςετʹ࢖͑Δ • "1*ϥούʔΛॻ͍ͯྑ͔ͬͨ • ৑௕ίʔυ͕গͳ͘ɺҙਤ͕໌֬ʹ • ίʔυิ׬΋շద
  62. ·ͱΊ 62 Copyright (C) DeNA Co.,Ltd. All Rights Reserved. •

    .PDLJOHKBZ͸4XJGUͷ)5514UVCϥΠϒϥϦ • )551௨৴ͷςετʹ࢖͑Δ • "1*ϥούʔΛॻ͍ͯྑ͔ͬͨ • ৑௕ίʔυ͕গͳ͘ɺҙਤ͕໌֬ʹ • ίʔυิ׬΋շద )5514UVC͸ ͓֮͑ͯ͘ͱ෢ثͱͯ͠໾ཱ͔ͭ΋ʂʁ
  63. એ఻ 63 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

  64. iOSDC ͷ CfP ҰཡΛݟΕΔαʔϏεΛ ϓϥΠϕʔτͰ࡞Γ·ͨ͠ʂ 64 Copyright (C) DeNA Co.,Ltd.

    All Rights Reserved. h(p://iosdc-cfps.penginmura.tech/ ࠓޙ΋ػೳ௥ՃΛ༧ఆ
  65. %F/"͔Β͸ ໊͕ొஃ͠·͢ʂ 65 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.

    ϒʔε΋΍Γ·͢ʂ
  66. &OKPZEFWFMPQNFOU XJUI)551TUVCT 66 Copyright (C) DeNA Co.,Ltd. All Rights Reserved.