146

equals()メソッドのないクラスがあり、そのクラスにソースがないとします。そのクラスの2つのインスタンスで同等性を主張したいと思います。

複数のアサートを実行できます。

assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...

初期のアサーションが失敗した場合、完全な平等の全体像が得られないため、このソリューションは好きではありません。

手動で比較して結果を追跡できます。

String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
    errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
    errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);

これは私に完全な平等の全体像を与えますが、不格好です(そして私は起こりうるヌルの問題を説明していません)。3番目のオプションはComparatorを使用することですが、compareTo()はどのフィールドが同等に失敗したかを教えてくれません。

サブクラス化して等しい(ugh)をオーバーライドせずに、オブジェクトから必要なものを取得するためのより良い方法はありますか?

4

23 に答える 23

81

Mockitoはリフレクション マッチャーを提供します。

最新バージョンの Mockito を使用するには:

Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual));

古いバージョンの場合:

Assert.assertThat(actual, new ReflectionEquals(expected, excludeFields));
于 2015-04-22T09:37:39.523 に答える
14

少し古いことは承知していますが、お役に立てば幸いです。

私はあなたと同じ問題に遭遇したので、調査の結果、これと似たような質問はほとんど見つかりませんでした.解決策を見つけた後、他の人を助けることができると思ったので、同じ質問に答えています.

この同様の質問の最も投票された回答(作成者が選んだ回答ではありません) が、あなたに最も適した解決策です。

基本的にはUnitilsというライブラリを使うことで成り立っています。

これは使用です:

User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);

Userクラスが実装していなくても、これは合格しますequals()より多くの例と、チュートリアルassertLenientEqualsで呼び出された非常にクールな assert を見ることができます。

于 2014-12-17T17:06:44.173 に答える
9

Apache commons lang ReflectionToStringBuilderを使用できます

テストする属性を 1 つずつ指定するか、不要なものを除外することができます。

String s = new ReflectionToStringBuilder(o, ToStringStyle.SHORT_PREFIX_STYLE)
                .setExcludeFieldNames(new String[] { "foo", "bar" }).toString()

次に、通常どおり 2 つの文字列を比較します。リフレクションが遅いという点については、これはテスト用であると想定しているため、それほど重要ではありません。

于 2012-08-28T07:33:43.317 に答える
4

ライブラリHamcrest 1.3 Utility Matchersには、equals の代わりにリフレクションを使用する特別なマッチャーがあります。

assertThat(obj1, reflectEquals(obj2));
于 2015-01-07T10:48:15.127 に答える
2

Shazamcrestを使用すると、次のことができます。

assertThat(obj1, sameBeanAs(obj2));
于 2018-09-12T17:36:10.630 に答える
1

リフレクションを使用して、完全な同等性テストを「自動化」できます。単一のフィールドに対して作成した同等性の「追跡」コードを実装してから、リフレクションを使用して、オブジェクト内のすべてのフィールドでそのテストを実行できます。

于 2012-08-27T18:50:17.383 に答える
1

フィールドごとに比較します。

assertNotNull("Object 1 is null", obj1);
assertNotNull("Object 2 is null", obj2);
assertEquals("Field A differs", obj1.getFieldA(), obj2.getFieldA());
assertEquals("Field B differs", obj1.getFieldB(), obj2.getFieldB());
...
assertEquals("Objects are not equal.", obj1, obj2);
于 2012-08-27T18:23:11.567 に答える
0

私はすべての答えを試しましたが、実際には何もうまくいきませんでした。

そこで、ネストされた構造に深く入り込むことなく、単純な Java オブジェクトを比較する独自のメソッドを作成しました...

すべてのフィールドが一致するか、不一致の詳細を含む文字列の場合、メソッドは null を返します。

getter メソッドを持つプロパティのみが比較されます。

使い方

        assertNull(TestUtils.diff(obj1,obj2,ignore_field1, ignore_field2));

不一致がある場合の出力例

出力には、比較されたオブジェクトのプロパティ名とそれぞれの値が表示されます

alert_id(1:2), city(Moscow:London)

コード (Java 8 以降):

 public static String diff(Object x1, Object x2, String ... ignored) throws Exception{
        final StringBuilder response = new StringBuilder();
        for (Method m:Arrays.stream(x1.getClass().getMethods()).filter(m->m.getName().startsWith("get")
        && m.getParameterCount()==0).collect(toList())){

            final String field = m.getName().substring(3).toLowerCase();
            if (Arrays.stream(ignored).map(x->x.toLowerCase()).noneMatch(ignoredField->ignoredField.equals(field))){
                Object v1 = m.invoke(x1);
                Object v2 = m.invoke(x2);
                if ( (v1!=null && !v1.equals(v2)) || (v2!=null && !v2.equals(v1))){
                    response.append(field).append("(").append(v1).append(":").append(v2).append(")").append(", ");
                }
            }
        }
        return response.length()==0?null:response.substring(0,response.length()-2);
    }
于 2019-02-01T16:58:17.310 に答える
-1

投稿した比較コードをいくつかの静的ユーティリティ メソッドに入れることはできますか?

public static String findDifference(Type obj1, Type obj2) {
    String difference = "";
    if (obj1.getFieldA() == null && obj2.getFieldA() != null
            || !obj1.getFieldA().equals(obj2.getFieldA())) {
        difference += "Difference at field A:" + "obj1 - "
                + obj1.getFieldA() + ", obj2 - " + obj2.getFieldA();
    }
    if (obj1.getFieldB() == null && obj2.getFieldB() != null
            || !obj1.getFieldB().equals(obj2.getFieldB())) {
        difference += "Difference at field B:" + "obj1 - "
                + obj1.getFieldB() + ", obj2 - " + obj2.getFieldB();
        // (...)
    }
    return difference;
}

このメソッドを JUnit で次のように使用できます。

assertEquals("オブジェクトが等しくありません", "", findDifferences(obj1, obj));

これは不格好ではなく、違いが存在する場合は、違いに関する完全な情報を提供します(通常の assertEqual 形式では正確ではありませんが、すべての情報を取得できるので、良いはずです)。

于 2012-08-27T18:33:24.140 に答える
-2

あなたのコメントから他の回答まで、あなたが何を望んでいるのかわかりません。

議論のために、クラスが equals メソッドをオーバーライドしたとしましょう。

したがって、UT は次のようになります。

SomeType expected = // bla
SomeType actual = // bli

Assert.assertEquals(expected, actual). 

これで完了です。さらに、アサーションが失敗すると、「完全な等価性」を得ることができません。

私が理解していることから、型が equals をオーバーライドしたとしても、「完全な等値図」を取得したいので、それに興味がないと言われています。したがって、 equals を拡張してオーバーライドしても意味がありません。

したがって、オプションが必要です。プロパティごとに比較するか、リフレクションまたはハードコードされたチェックを使用して、後者をお勧めします。または:これらのオブジェクトの人間が読める表現を比較します。

たとえば、XML ドキュメントと比較したい型をシリアル化し、結果の XML を比較するヘルパー クラスを作成できます。この場合、正確に等しいものとそうでないものを視覚的に確認できます。

このアプローチでは、全体像を把握する機会が得られますが、比較的面倒です (また、最初は少しエラーが発生しやすくなります)。

于 2012-08-27T19:28:33.913 に答える
-3

次のように、クラスの equals メソッドをオーバーライドできます。

@Override
public int hashCode() {
    int hash = 0;
    hash += (app != null ? app.hashCode() : 0);
    return hash;
}

@Override
public boolean equals(Object object) {
    HubRule other = (HubRule) object;

    if (this.app.equals(other.app)) {
        boolean operatorHubList = false;

        if (other.operator != null ? this.operator != null ? this.operator
                .equals(other.operator) : false : true) {
            operatorHubList = true;
        }

        if (operatorHubList) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

クラスの 2 つのオブジェクトを比較したい場合は、何らかの方法で equals と hash code メソッドを実装する必要があります。

于 2012-08-27T18:20:00.173 に答える