Help us understand the problem. What is going on with this article?

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

はじめに

「製品コードでは構造体を比較しないけど、テスト時は比較したい」ということはありませんか: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でご連絡ください!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away