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

Unit Test with SwiftyMocky

Yosuke Imairi
September 24, 2019

Unit Test with SwiftyMocky

Mockolo のほうがおすすめ : https://github.com/uber/mockolo

How to use SwiftyMocky for iOS app unit tests
example: https://github.com/imairi/SwiftyMockyDemo

Yosuke Imairi

September 24, 2019
Tweet

More Decks by Yosuke Imairi

Other Decks in Technology

Transcript

  1. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    Unit Test with SwiftyMocky

    View Slide

  2. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    ⾃⼰紹介
    2
    Yosuke Imairi
    • JapanTaxi (2017.5 -)
    • iOS app Developer

    View Slide

  3. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    iOSDC2019でブース出展しました
    3
    JapanTaxiのサービス全体のデモ
    - 「JapanTaxi」アプリでタクシーを
    呼ぶ
    - ドライバーが応答
    - 降⾞時の⽀払い

    View Slide

  4. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    iOSDC2019でブース出展しました
    4
    「JapanTaxi」アプリの技術スタックペーパー
    - iOS, Android で利⽤している⾔語
    - 導⼊しているアーキテクチャやライブラリ

    View Slide

  5. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    iOSDC2019でブース出展しました
    5
    「JapanTaxi」アプリの技術スタックペーパー
    - iOS, Android で利⽤している⾔語
    - 導⼊しているアーキテクチャやライブラリ

    View Slide

  6. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    SwiftyMocky
    6
    ⁃ SwiftのProtocolをモック化できるライブラリ
    ⁃ SouceryのAutoMockableを利⽤
    ⁃ ジェネリクスにも対応
    ⁃ Given: モックで返す値を設定
    ⁃ Verify: モック内のプロパティ/メソッド呼び出し回数を取得
    ⁃ Perform: モック内のメソッド処理後の追加処理

    View Slide

  7. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ①
    7
    ⁃ モック化したいProtocolをAutoMockableに準拠させる
    protocol ToBeMocked: AutoMockable {
    // ...
    }
    //sourcery: AutoMockable
    protocol ToBeMocked {
    // ...
    }
    ⁃ アノテーションをはるだけでもOK

    View Slide

  8. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ①
    8
    ⁃ メインターゲット
    protocol User {
    var name: String { get }
    var age: Int { get }
    func profile() -> String
    func update(age: Int)
    func update(name: String, completion:(() -> Void))
    }
    ⁃ テストターゲット
    //sourcery: AutoMockable
    extension User {} ⇒ User をモック化の対象に

    View Slide

  9. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ②
    9
    ⁃ Mockfileの作成
    $ swiftymocky setup

    View Slide

  10. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ②
    10
    ⁃ Mockfile
    sourceryCommand: null
    SwiftyMockyDemoTests:
    sources:
    include:
    - ./SwiftyMockyDemo
    - ./SwiftyMockyDemoTests
    output: ./SwiftyMockyDemoTests/Mock.generated.swift
    targets:
    - SwiftyMockyDemoTests
    testable:
    - SwiftyMockyDemo
    import:
    - Foundation

    View Slide

  11. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ③
    11
    ⁃ Mock(Mock.generated.swift)の⽣成
    $ swiftymocky generate

    View Slide

  12. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ③
    12
    ⁃ Mock.generated.swift
    // MARK: - User
    open class UserMock: User, Mock {

    public var name: String {
    get { invocations.append(.p_name_get); return __p_name ??
    givenGetterValue(.p_name_get, "UserMock - stub value for name was not
    defined") }
    @available(*, deprecated, message: "Using setters on readonly variables
    is deprecated, and will be removed in 3.1. Use Given to define stubbed property
    return value.")
    set { __p_name = newValue }
    }

    open func profile() -> String {
    addInvocation(.m_profile)
    let perform = methodPerformValue(.m_profile) as? () -> Void
    perform?()

    View Slide

  13. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    モックの準備 ③
    13
    ⁃ もし、なにか問題があれば…
    $ swiftymocky doctor

    View Slide

  14. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    UnitTestでモックを使う ①
    14
    ⁃ 「Protocol名 + Mock」クラス
    ⁃ モックに対して情報を与える(Given)
    let user = UserMock()
    user.given(.name(getter: "imairi"))
    user.given(.age(getter: 32))
    user.given(.profile(willReturn: "いまいりようすけ 32歳"))

    View Slide

  15. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    UnitTestでモックを使う ②
    15
    ⁃ モックで動作確認をする(Verify)
    ⁃ モック内のプロパティ/メソッドが呼ばれた回数を検査
    ⁃ Countにはさまざまな種類が⽤意されている
    user.verify(.profile(), count: 3)
    user.verify(.profile(), count: .never)
    user.verify(.profile(), count: .more(than: 2))
    user.verify(.profile(), count: .custom({ count -> Bool in
    guard self.user.age < 30 && count == 1 else {
    return true
    }
    return false
    }))

    View Slide

  16. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    UnitTestでモックを使う ②
    16
    ⁃ モックで動作確認をする(Verify)
    ⁃ 引数を考慮した検査も⾏える
    // 引数もチェックする
    user.verify(.update(age: .value(33)), count: 1)
    // 引数はチェックしない
    user.verify(.update(age: .any), count: 1)

    View Slide

  17. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    UnitTestでモックを使う ③
    17
    ⁃ モックのメソッドが呼ばれた後の処理(Perform)
    // UnitTest
    user.perform(.update(name: .any, completion: .any,
    perform: { (name, completion) in
    completion()
    }))
    // UserProtocol
    func update(name: String, completion:(() -> Void))
    ⁃ Closureを引数にとるメソッドをモック化し、UnitTestか
    ら操作できない場合はPerformを使う必要あり

    View Slide

  18. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    Sample codes
    18
    ⁃ github.com/imairi/SwiftyMockyDemo

    View Slide

  19. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved
    まとめ
    19
    ⁃ SwiftyMockyでProtocolのモック化がかんたんにできる
    ⁃ Protocolを多⽤しているプロジェクトに向いている
    ⁃ メソッドの呼ばれた回数の検査でテストの幅も広がる
    ⁃ モックがかんたんに作れるとテストを書く気になれる

    View Slide

  20. จষɾը૾౳ͷ಺༰ͷແஅసࡌٴͼෳ੡౳ͷߦҝ͸͝ԕྀ͍ͩ͘͞ɻ
    Proprietary and Confidential ©2017 JapanTaxi, Inc.
    All Rights Reserved
    ˟102-0094ɹ౦ژ౎ઍ୅ా۠لඌҪொ3-12
    3-12 Kioicho Chiyoda-ku, Tokyo 102-0094 Japan
    TEL 03-6265-6265ɹFAX 03-3239-8115
    www.japantaxi.co.jp

    View Slide