Mockolo のほうがおすすめ : https://github.com/uber/mockolo
How to use SwiftyMocky for iOS app unit tests example: https://github.com/imairi/SwiftyMockyDemo
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedUnit Test with SwiftyMocky
View Slide
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reserved⾃⼰紹介2Yosuke Imairi• JapanTaxi (2017.5 -)• iOS app Developer
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservediOSDC2019でブース出展しました3JapanTaxiのサービス全体のデモ- 「JapanTaxi」アプリでタクシーを呼ぶ- ドライバーが応答- 降⾞時の⽀払い
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservediOSDC2019でブース出展しました4「JapanTaxi」アプリの技術スタックペーパー- iOS, Android で利⽤している⾔語- 導⼊しているアーキテクチャやライブラリ
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservediOSDC2019でブース出展しました5「JapanTaxi」アプリの技術スタックペーパー- iOS, Android で利⽤している⾔語- 導⼊しているアーキテクチャやライブラリ
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedSwiftyMocky6⁃ SwiftのProtocolをモック化できるライブラリ⁃ SouceryのAutoMockableを利⽤⁃ ジェネリクスにも対応⁃ Given: モックで返す値を設定⁃ Verify: モック内のプロパティ/メソッド呼び出し回数を取得⁃ Perform: モック内のメソッド処理後の追加処理
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ①7⁃ モック化したいProtocolをAutoMockableに準拠させるprotocol ToBeMocked: AutoMockable {// ...}//sourcery: AutoMockableprotocol ToBeMocked {// ...}⁃ アノテーションをはるだけでもOK
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ①8⁃ メインターゲットprotocol User {var name: String { get }var age: Int { get }func profile() -> Stringfunc update(age: Int)func update(name: String, completion:(() -> Void))}⁃ テストターゲット//sourcery: AutoMockableextension User {} ⇒ User をモック化の対象に
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ②9⁃ Mockfileの作成$ swiftymocky setup
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ②10⁃ MockfilesourceryCommand: nullSwiftyMockyDemoTests:sources:include:- ./SwiftyMockyDemo- ./SwiftyMockyDemoTestsoutput: ./SwiftyMockyDemoTests/Mock.generated.swifttargets:- SwiftyMockyDemoTeststestable:- SwiftyMockyDemoimport:- Foundation
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ③11⁃ Mock(Mock.generated.swift)の⽣成$ swiftymocky generate
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ③12⁃ Mock.generated.swift// MARK: - Useropen 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 notdefined") }@available(*, deprecated, message: "Using setters on readonly variablesis deprecated, and will be removed in 3.1. Use Given to define stubbed propertyreturn value.")set { __p_name = newValue }}…open func profile() -> String {addInvocation(.m_profile)let perform = methodPerformValue(.m_profile) as? () -> Voidperform?()…
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedモックの準備 ③13⁃ もし、なにか問題があれば…$ swiftymocky doctor
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedUnitTestでモックを使う ①14⁃ 「Protocol名 + Mock」クラス⁃ モックに対して情報を与える(Given)let user = UserMock()user.given(.name(getter: "imairi"))user.given(.age(getter: 32))user.given(.profile(willReturn: "いまいりようすけ 32歳"))
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedUnitTestでモックを使う ②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 inguard self.user.age < 30 && count == 1 else {return true}return false}))
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedUnitTestでモックを使う ②16⁃ モックで動作確認をする(Verify)⁃ 引数を考慮した検査も⾏える// 引数もチェックするuser.verify(.update(age: .value(33)), count: 1)// 引数はチェックしないuser.verify(.update(age: .any), count: 1)
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedUnitTestでモックを使う ③17⁃ モックのメソッドが呼ばれた後の処理(Perform)// UnitTestuser.perform(.update(name: .any, completion: .any,perform: { (name, completion) incompletion()}))// UserProtocolfunc update(name: String, completion:(() -> Void))⁃ Closureを引数にとるメソッドをモック化し、UnitTestから操作できない場合はPerformを使う必要あり
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights ReservedSample codes18⁃ github.com/imairi/SwiftyMockyDemo
Proprietary and Confidential ©2017 JapanTaxi, Inc. All Rights Reservedまとめ19⁃ SwiftyMockyでProtocolのモック化がかんたんにできる⁃ Protocolを多⽤しているプロジェクトに向いている⁃ メソッドの呼ばれた回数の検査でテストの幅も広がる⁃ モックがかんたんに作れるとテストを書く気になれる
จষɾը૾ͷ༰ͷແஅసࡌٴͼෳͷߦҝ͝ԕྀ͍ͩ͘͞ɻProprietary and Confidential ©2017 JapanTaxi, Inc.All Rights Reserved˟102-0094ɹ౦ژઍా۠لඌҪொ3-123-12 Kioicho Chiyoda-ku, Tokyo 102-0094 JapanTEL 03-6265-6265ɹFAX 03-3239-8115www.japantaxi.co.jp