目的
- テストの際に、都度Mockクラスを作るのが面倒なので楽したい
探してみるとCuckooというライブラリがあったので使ってみる。
導入
readmeにあるようにすすめれば大丈夫
https://github.com/Brightify/Cuckoo
Run Script
テストターゲットのBuild PhasesにRun Scriptを足すように言われるが、Compile Sourcesより先に実行されるようにしておくと良さそう(一瞬はまった)
テストのたびにファイルのコメントのタイムスタンプが更新されて鬱陶しいので、--no-timestamp
オプションを追加しておく
# Define output file. Change "$PROJECT_DIR/${PROJECT_NAME}Tests" to your test's root source folder, if it's not the default name.
OUTPUT_FILE="$PROJECT_DIR/${PROJECT_NAME}Tests/GeneratedMocks.swift"
echo "Generated Mocks File = $OUTPUT_FILE"
# Define input directory. Change "${PROJECT_DIR}/${PROJECT_NAME}" to your project's root source folder, if it's not the default name.
INPUT_DIR="${PROJECT_DIR}/${PROJECT_NAME}"
echo "Mocks Input Directory = $INPUT_DIR"
# Generate mock files, include as many input files as you'd like to create mocks for.
"${PROJECT_DIR}/Carthage/Checkouts/Cuckoo/run" generate --no-timestamp --testable "$PROJECT_NAME" \
--output "${OUTPUT_FILE}" \
"$INPUT_DIR/MyModel.swift" \
# ... and so forth, the last line should never end with a backslash
# After running once, locate `GeneratedMocks.swift` and drag it into your Xcode test target group.
MyModel.swift以降に、モック化したいファイルを追記。つまり、モック対象が増えるたびにここをアップデートする必要がある。。。
例
あんまりいい例が思いつかなかったんですが...
ViewModelのとあるメソッドがModelのメソッドを実行していること
を確認したい場合の例
テスト対象
MyViewModel.swift
class MyViewModel {
let model: MyModel
init(_ model: MyModel) {
self.model = model
}
func doSomethingWithModel() {
model.someRequest()
}
}
モック化したい
MyModel.swift
class MyModel {
func someRequest() {
// APIで云々...
}
}
テストコード
MyViewModelTest.swift
class MyViewModelTest: XCTestCase {
var mock: MockMyModel!
override func setUp() {
// 対象にしたいprotocol/classの頭にMockをつけたclassが用意されるので使う
mock = MockMyModel()
stub(mock) { (mock) in
// メソッドがコールされても何もしないことを設定する
when(mock.someRequest()).thenDoNothing()
}
}
func testDoSomethingWithModel() {
// mockを注入
let viewModel = MyViewModel(mock)
viewModel.doSomethingWithModel()
// mockのメソッドが呼ばれていることを確認する
verify(mock, times(1)).someRequest()
}
}
流石に自分でモックを書くよりは早そうですね!