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

通信処理を差し替えてみた話

Tatsuya Tanaka
February 15, 2017

 通信処理を差し替えてみた話

URLProtocolとMethod Swizzlingの話
#potatotips 37

Tatsuya Tanaka

February 15, 2017
Tweet

More Decks by Tatsuya Tanaka

Other Decks in Technology

Transcript

  1. ௨৴ॲཧΛࠩ͠ସ͑ͯΈͨ࿩

    View Slide

  2. ࣗݾ঺հ
    • ాதୡ໵ (@tattn)
    • Ϡϑʔͷ2016೥৽ଔ

    View Slide

  3. Qiitaͱ͔Twitterͱ͔΍ͬͯ·͢
    • ։ൃ͕ര଎ʹͳΔSwift༻XcodeϓϥάΠϯΛ·ͱΊͯΈͨ
    • ࢖͏ͱख์ͤͳ͘ͳΔSwift Extensionू (Swift3൛)
    @tanakasan2525

    View Slide

  4. APIͷϢχοτςετͲ͏ͯ͠·͢
    ͔ʁ

    View Slide

  5. DIʁ ϥΠϒϥϦʁ

    View Slide

  6. MockingjayศརͰ͢ΑͶ

    View Slide

  7. Mockingjay
    https://github.com/kylef/Mockingjay
    let body = [ "user": "Kyle" ]
    stub(uri("/{user}/{repository}"), json(body))

    View Slide

  8. Ͳ͏͍͏࢓૊ΈͰಈ͍ͯΔΜͩΖ͏ !

    View Slide

  9. ௐ΂ͯΈΔͱ

    View Slide

  10. URLProtocolͱMethod Swizzling
    Λ࢖ͬͯ௨৴ॲཧΛࠩ͠ସ͍͑ͯ·͠
    ͨ

    View Slide

  11. URLProtocol
    https://developer.apple.com/reference/foundation/urlprotocol
    αϙʔτ֎ͷϓϩτίϧͰ௨৴͢Δ৔߹΍
    ϦΫΤετΛಠࣗͷํ๏Ͱॲཧ͢Δ࣌ʹ࢖͏Ϋϥεɻ

    View Slide

  12. Mock༻ͷURLProtocol
    public class MockURLProtocol: URLProtocol {
    override open func startLoading() {
    let jsonString = "{\"mock\": \"data\"}"
    let json = jsonString.data(using: .utf8)!
    self.client?.urlProtocol(self, didLoad: json)
    self.client?.urlProtocolDidFinishLoading(self)
    }
    // ͦͷଞϝιου͸লུ
    }

    View Slide

  13. Method SwizzlingͰϞοΫ༻ͷURLProtocol
    ʹࠩ͠ସ͑
    public extension URLSessionConfiguration {
    public class func setup() {
    let `default` = class_getClassMethod(URLSessionConfiguration.self,
    #selector(getter: URLSessionConfiguration.default))
    let swizzled = class_getClassMethod(URLSessionConfiguration.self,
    #selector(getter: URLSessionConfiguration.mock))
    method_exchangeImplementations(`default`, swizzled)
    }
    private dynamic class var mock: URLSessionConfiguration {
    let configuration = self.mock
    configuration.protocolClasses?.insert(MockURLProtocol.self, at: 0)
    URLProtocol.registerClass(MockURLProtocol.self)
    return configuration
    }
    }

    View Slide

  14. ֶ͔ͤͬ͘ΜͩͷͰϥΠϒϥϦԽ͠·
    ͨ͠ !

    View Slide

  15. Replacer
    https://github.com/tattn/Replacer
    ௨৴ͷελϒԽ΍Method SwizzlingΛαϙʔτ͢ΔϥΠϒϥϦ

    View Slide

  16. Method ChainͰΦϓγϣϯΛઃఆ͠·͢
    self.urlStub
    .url("echo.jsontest.com/[a-z]+/.*")
    .httpMethod(.post)
    .json(["test": "data"])
    .delay(1.5)

    View Slide

  17. QuickͱAlamofireͰͷελϒԽ
    describe("Quick compatibility test") {
    it("returns mock data") {
    let url = "http://echo.jsontest.com/key/value/one/two"
    var json: [String: String]?
    Alamofire.request(url, method: .post).responseJSON { response in
    json = response.result.value as? [String: String]
    }
    expect(json?["test"]).toEventually(equal("data"))
    }
    }

    View Slide

  18. ओͳػೳ
    • ௨৴ͷελϒԽ
    • XCTestҎ֎ (Host Application΋ؚΉ) Ͱ΋࢖༻Մೳ
    • Method Swizzlingͷαϙʔτػೳ
    ͳͲͰ͢ɻ

    View Slide

  19. ྑ͔ͬͨΒ࢖ͬͯΈ͍ͯͩ͘͞ !
    (ʁʁ)ʻ ܅͸⭐͕େ޷͖ͳϑϨϯζͳΜͩͶʂ

    View Slide

  20. ͋ɺͦ͏͍͑͹ɺɺɺ

    View Slide

  21. ࡞͍ͬͯΔ࣌ʹSwiftͷόάʹؾ͕෇͖·ͨ͠
    ؀ڥ: Xcode 8.2, Swift 3.0.2

    View Slide

  22. άϩʔόϧఆٛ͞Εͨؔ਺ʹϞδϡʔϧ໊Λ෇͚
    Δͱɺ@discardableResult͕ਖ਼ৗʹಈ࡞͠ͳ͍

    View Slide

  23. ઌఔௐ΂ͯΈΔͱɺमਖ਼͞ΕͨΈ͍ͨͰ͢ !
    https://bugs.swift.org/browse/SR-3665
    Fix @discardableResult when invoking function with explicit
    namespace #7201

    View Slide

  24. SwiftͷਐԽɾվળ͸ࢭ
    ·Βͳ͍Ͱ͢Ͷʂ !

    View Slide

  25. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝
    ·ͨ͠ʂ

    View Slide