LoginSignup
24
9

More than 3 years have passed since last update.

テスト時のみEquatableプロトコルに準拠させる方法(Swift)

Last updated at Posted at 2020-01-13

はじめに

「製品コードでは構造体を比較しないけど、テスト時は比較したい」ということはありませんか:interrobang:

Equatable プロトコルに準拠することで、構造体同士を == で比較できるようになります。

FooEntity.swift
struct FooEntity: Equatable {
    let name: String
    let age: Int
}
FooTests.swift
let fooEntity1 = FooEntity(name: "foo", age: 18)
let fooEntity2 = FooEntity(name: "foo", age: 24)

// `Equatable` に準拠しているため、ビルドが通る
XCTAssertEqual(fooEntity1, fooEntity2) // `age` が異なるのでテストは失敗する

このように製品コードで直接 Equatable プロトコルに準拠させる方法が考えられますが、「 テスト時のみ比較したい 」という意図が読み取れません。

Twitterでテスト時のみ Equatable プロトコルに準拠させる方法を教えていただいたので、備忘録として残します。

個人的な結論:テスト時のみEquatableプロトコルに準拠させる必要はない

本題に入る前にまず私の結論を言います。
本末転倒ですが、Twitterでいろいろ意見を頂いた結果、私は製品コードで Equatable プロトコルに準拠させればいいと結論付けました。
理由は以下の通りです。

  • Equatable プロトコルに準拠しても副作用がほとんどない
    • コンパイラが自動生成する == のコードによるオーバーヘッドくらい
  • テスト時のみ Equtable プロトコルに準拠させる方法はどれもデメリットがある
    • 詳しくは後述する
  • 「構造体が比較できる」ことを当たり前の言語仕様と考えれば、製品に不要なコードが含まれていることにはならない
    • StringやIntも Equatable プロトコルに準拠しており、比較しなくても普通に使っている

方法①:テスト用のマクロを作る

@_ha1f さんから教えていただきました。

テスト用のマクロを作り、テスト時のみエクステンションで準拠させます。

FooEntity.swift
struct FooEntity {
    let name: String
    let age: Int
}

#if TEST
extension FooEntity: Equatable {}
#endif

これは思いつかなかったので目から鱗でした。
「テスト時のみ比較する」という意図が明確にわかります。

ただし、「 マクロが増える 」というデメリットがあります。

方法②:テストターゲットで準拠させる

方法①のエクステンションをテストターゲット側に記述すれば、マクロが不要になります。

FooTests.swift
@testable import FooTarget

extension FooEntity: Equatable {
    public static func == (lhs: FooEntity, rhs: FooEntity) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
}

しかし、 == のコードを自分で実装し、 public にする必要があります。
(なぜその必要があるかの言語仕様までは調べていません)

これは「 構造体に新しくプロパティを追加したときに、修正が必要になる 」というデメリットがあります。
修正しなくても警告やエラーが発生しないため、忘れがちになります。

おわりに

方法①も②もデメリットがあることがわかりました。
私はできる限りテスト時のみ使うコードを製品に含めたくないので、デメリットがなければ採用していました。

Twitterで議論が広がると、自分だけでは考えつかなかったことを学べるので、とてもありがたいです。
他にご意見のある方がいらっしゃれば、遠慮なくコメントやTwitterでご連絡ください!

24
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
9