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

Unit Test with SwiftyMocky

63bf22db8ab8da3851da34d2e0cb0c69?s=47 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

63bf22db8ab8da3851da34d2e0cb0c69?s=128

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
  2. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved ⾃⼰紹介

    2 Yosuke Imairi • JapanTaxi (2017.5 -) • iOS app Developer
  3. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved iOSDC2019でブース出展しました

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

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

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

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

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

    9 ⁃ Mockfileの作成 $ swiftymocky setup
  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
  11. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved モックの準備 ③

    11 ⁃ Mock(Mock.generated.swift)の⽣成 $ swiftymocky generate
  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?() …
  13. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved モックの準備 ③

    13 ⁃ もし、なにか問題があれば… $ swiftymocky doctor
  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歳"))
  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 }))
  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)
  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を使う必要あり
  18. Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved Sample

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

    19 ⁃ SwiftyMockyでProtocolのモック化がかんたんにできる ⁃ Protocolを多⽤しているプロジェクトに向いている ⁃ メソッドの呼ばれた回数の検査でテストの幅も広がる ⁃ モックがかんたんに作れるとテストを書く気になれる
  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