LoginSignup
2
2

EqualsVerifierを使ったらequals()のテストが一瞬で終わった

Last updated at Posted at 2018-02-25

はじめに

Javaでクラスの同値性をチェックする場合、equals() および hashCode() を適切に実装する必要があります1。通常は自前で実装しないのでまず間違いはないと思いますが、テストをしないのは不安です。

効率のいい方法がないかと探していたところ、EqualsVerifierというライブラリを見つけました。

インストール

Getting StartedにMavenでの設定方法が書かれています。他のツールの場合はMvnRepositoryを参照してください。

使い方

例えば以下のようなNameクラスがあります。この equals() hashCode() はIntelliJ IDEAで自動生成したものです。

import java.util.Objects;

public final class Name {
    private final String name;

    public Name of(String name) {
        return new Name(name);
    }

    public Name(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Name name1 = (Name) o;
        return Objects.equals(name, name1.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

これに対するテストは次の通りです(JUnit 4.12を使用)。

import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.Test;

import java.sql.Timestamp;

public final class EqualsVerifierTest {
    @Test
    public void test_name() {
        EqualsVerifier.forClass(Name.class).verify();
    }
}

これだけです。簡単ですね。

もちろんこれでは本当にテストしたか分からないので、例えば、equals()の一般契約に従っていない、Timestampクラスでテストします。

EqualsVerifier.forClass(Timestamp.class).verify();

以下のようなエラーが出ました。

java.lang.AssertionError: Overloaded: More than one equals method found.
Signature should be: public boolean equals(Object obj)
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages

特定のフィールドを除外したい場合

Ignoring fieldsにありますが、例えば、以下のようにして除外できます。詳細はドキュメントを参照してください。

  • withIgnoredFields メソッドに、無視するフィールド名を渡す
  • Javaのキーワード transient を使う

自分としては transient を使うのがいいかなぁと思います。

動作原理

Why, what, how?の下の方に書かれていますが、だいたい以下の通りです。ちょっと黒魔術ですね。

  1. モッキングフレームワークと同じように、コンストラクタを呼ばずにインスタンスを生成する。
  2. リフレクションを使ってフィールドに値を設定する。
  3. これらに対して equals()hashCode() が期待される結果になるか確認する。
  4. equals() メソッドのシグネチャを調べ、オーバーロードでなくオーバーライドを使用していることを確認する。

おわりに

楽をしたい気持ちは大切だと思いました( ´ω`)

  1. Effective Java 第2版 「項目8 equalsをオーバーライドする時は一般契約に従う」および「項目9 equlsをオーバーライドする時は、常にhashCodeをオーバーライドする」を参照。

2
2
2

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
2
2