Nimbleでテストを書いていた際に、共通部分をPredicate
として自作してまとめたいことがあったので、実装の方法と簡単なサンプルを記しておきます。
実装方法
Quick/NimbleのMatchersの中で、beEmpty
やbeNil
を見るとわかりやすいです。
matcherで使うために、Predicate
を返すメソッドを定義する必要があります。
Predicate
はPredicate.simple
やPredicate.simpleNilable
を使うと簡単に、生成することが出来ます。
func hoge<T>() -> Predicate<T> { return Predicate.simple("hoge") { // 判定処理 } }
PredicateStatus
はmatches
、doesNotMatch
、fail
の3つからなるenum
です。
値 | 説明 |
---|---|
matches | 判定条件に合致 |
doesNotMatch | 判定条件に合致しない |
fail | 入力が上の2つのいずれの状態にもなりえない |
.fail
は特殊ですが、ドキュメントコメントにあるように、nil
がexpect
に入ったときなどに起こります。
expect(nil).to(equal(1))
とexpect(nil).toNot(equal(1))
はどちらもマッチ扱いにならずfail
となります。
サンプル
その1: ダウンキャストして比較
func beA<T, U: Equatable>(_ object: U) -> Predicate<T> { return Predicate.simple("be a") { actual in guard let actual = try actual.evaluate() as? U else { return .fail } return PredicateStatus(bool: actual == object) } }
名前はCoreMatchers
から拝借しました。
ダウンキャストに失敗した場合は.fail
として、成功した場合は比較を行います。
条件式に対しては、PredicateStatus(bool: Bool)
を使うことで簡単にPredicateStatus
を作ることが出来ます。
その2: enumのassociated valueを比較
enum HogeCases { case hoge(count: Int) case fuga } func beHogeCountIs(_ expected: Int) -> Predicate<HogeCases> { return Predicate.simple("be hoge count is") { actual in guard let actual = try actual.evaluate() else { return .fail } guard case let .hoge(count) = actual else { return .doesNotMatch } return PredicateStatus(bool: count == expected) } } // 利用例 expect(HogeCases.hoge(count: 1)).to(beHogeCountIs(1))
enum
のassociated valueを見る時のPredicate
です。
.hoge
でなかった場合は、toNot
にしたときに引っかかってほしいため、doesNotMatch
を返します。
実際のケースでもっと複雑な比較になっても、一度Predicate
を作っておけば、複数のテストケースで利用でき、見通しが良くなります。