10

Javaアプリケーションを開発するとき、私はしばしばObjectメソッド(通常はequalsとhashCode)をオーバーライドします。すべてのクラスのObjectメソッドのコントラクトを順守していることを体系的に確認する方法が必要です。たとえば、等しいオブジェクトの場合、ハッシュコードも等しいことを表明するテストが必要です。私はJUnitテストフレームワークを使用しているので、できれば、これらのテストを自動的に生成できるJUnitソリューション、またはすべてのクラスにアクセスして契約が守られていることを確認できるテストケースが必要です。

JDK6とJUnit4.4を使用しています。

4

8 に答える 8

2
    public static void checkObjectIdentity(Object a1, Object a2, Object b1) {
        assertEquals(a1, a2);
        assertEquals(a2, a1);
        assertNotSame(a1, a2);
        assertEquals(a1.hashCode(), a2.hashCode());
        assertFalse(a1.equals(b1));
        assertFalse(a2.equals(b1));
        assertFalse(b1.equals(a1));
        assertFalse(b1.equals(a2));
    }

使用法:

        checkObjectIdentity(新しい整数(3)、新しい整数(3)、新しい整数(4));

もっと良いものは考えられません。バグが見つかったら、checkObjectIdentity への新しい呼び出しを追加します。

于 2008-10-10T12:08:58.700 に答える
1

その質問についての最初の考えです(これは、1時間経ってもまだ答えがない理由を説明するかもしれません!?;)

質問に対する解決策を実装することになると、2 つの部分があるようです。

1/ 自分のすべてのクラスを取得します。簡単です。jar 名を指定すると、Junit テストの初期化メソッドは次のようになります。

  • そのjarがJUnit実行クラスパスにあるかどうかを確認します
  • その中のすべてのクラスを読み込んでロードする
  • equals() および hash() が宣言され、(リフレクションによって) 再定義されたもののみを記憶します。

2/ すべてのオブジェクトをテストする
...そしてそこに問題があります。これらのオブジェクトをインスタンス化する必要があります。つまり、2 つのインスタンスを作成し、それらを equals() テストに使用します。

つまり、コンストラクターが引数を取る場合は、次のことを考慮する必要があります。

  • プリミティブ型の引数 (int、boolean、float、...) または String の場合、制限値のすべての組み合わせ (String の場合、"xxx"、""、null の場合。int、0、-x、+x、-Integer の場合) .MIN、+Integer.MAX、...など)
  • 非プリミティブ型の場合、テストするオブジェクトのコンストラクターに渡されるインスタンスを構築します (つまり、そのパラメーターのコンストラクター パラメーターを再帰的に考慮する必要があります: プリミティブ型かどうか)。

最後に、これらのコンストラクター用に自動的に作成されたすべてのパラメーターが機能的に意味をなすわけではありません。つまり、これらの値の一部は、Assert が原因でインスタンスの構築に失敗します。これは検出する必要があります。

それでも可能だと思われます (必要に応じてコード チャレンジにすることもできます) が、最初に他の StackOverflow 読者がこの問題に対応できるようにしたいと思います。


組み合わせの問題を回避し、テスト関連のテスト値を実際のコード自体に近づけるために、コンストラクターの有効な値を表す文字列を使用して、専用の注釈を定義することをお勧めします。オブジェクトの 1 つの equals() オーバーライドされたメソッドのすぐ上に配置されます。

次に、これらの注釈値が読み取られ、それらから作成されたインスタンスが結合されて、equals() のテストが行​​われます。それは組み合わせの数を十分に抑えるでしょう

サイドノード: 一般的な JUnit テスト ケースでは、もちろん、テストに対する equals() ごとに、以下があることを確認します。

  • 上記のいくつかの注釈 (デフォルトのコンストラクターしか利用できない場合を除く)
  • 対応する hash() メソッドもオーバーライドされます (そうでない場合は、アサート例外がスローされ、そのクラスで失敗します)
于 2008-10-10T04:18:15.183 に答える
0

VonC は正しい軌道に乗っていると思いますが、(オブジェクト メソッドがテストされている) .class オブジェクトを受け取るパラメーター化されたテストの後に可変数のコンストラクター引数が続くなど、あまり洗練されていないものに落ち着くことさえあります。次に、リフレクションを使用して、渡された引数の型に一致するコンストラクターを見つけ、コンストラクターを呼び出す必要があります。このテストでは、渡されるパラメーターがオブジェクトの有効なインスタンスを作成すると想定します。

このソリューションの欠点は、このテスト クラスでテストする各クラスを「登録」する必要があり、有効な入力がコンストラクターに与えられていることを確認する必要があることです。これは必ずしも簡単ではありません。その観点から、とにかく各クラスのすべてのテストを手動で作成するよりも、これが多かれ少なかれ作業になるかどうかについて、私はフェンスにいます。

これがうまくいくと思われる場合は投票してください...もっと洗い流してほしい場合はコメントを残してください(それが実現可能な解決策であることが判明した場合は、とにかくこれを行うかもしれません)

于 2008-10-10T04:27:43.243 に答える
0

ここでは、プリミティブ パラメーターのみを使用してコンストラクターを使用して等値テストを行うための、最初の大まかな実装があります。それをコピーして test.MyClass.java ファイルに貼り付けて実行するだけです。

警告: 1720 行のコード (findbugs のエラーは 0、「変更された」checkstyle のエラーは 0、すべての関数の循環的複雑度は 10 未満)。

次のすべてのコードを参照してください:アノテーションによる Java クラスの equals 関数の自動テスト

于 2008-10-19T15:08:45.040 に答える
0

[ここのコミュニティ投稿、カルマは関係ありません;)]

ここにあなたのための別のコードチャレンジがあります:

JUnit テスト ケースを実装する1 つのJava クラスで、JUnit を起動できるメイン メソッドを備えています。

このクラスは次のことも行います。

  • hash() と equals() をオーバーライドする
  • いくつかの属性を定義します (プリミティブ型を使用)
  • デフォルトのコンストラクターだけでなく、パラメーターのさまざまな組み合わせを持ついくつかのコンストラクターも定義します
  • それらのコンストラクターに渡す「興味深い」値を列挙できる注釈を定義します
  • それらの「興味深い」値で equals() に注釈を付けます

テスト メソッドはクラス名パラメーター (ここではそれ自体になります) を取り、その名前のクラスに「興味深い値」の注釈を付けた equals() オーバーライド メソッドがあるかどうかを確認します。
存在する場合は、注釈に基づいて (それ自体の) 適切なインスタンスを構築し、equals() をテストします。

これは自己完結型のテスト クラスであり、アノテーション付きのオーバーライドされた equals() 関数を使用して任意のクラスに一般化できるメカニズムを定義します。

JDK6 と JUnit4.4 を使用してください

そのクラスは、空のJavaプロジェクトの適切なパッケージにコピーして貼り付ける必要があります...そして実行するだけです;)


ニコラスに応えて、さらに考えを追加するには(コメントを参照):

  • はい、テストに必要なデータは、テストされるクラス候補内にあります (つまり、equals をオーバーライドし、「自動テスター」が適切なインスタンスを構築するのに役立つもの)
  • 私はそれを正確に「テストロジック」とは見なしていませんが、同等のことを行うと想定されていることに関する有用なコメントとして(そして、前述のテスターに​​よって悪用されるデータとして偶然に;))

潜在的なテスト データを表す注釈は、決してクラス自体に含まれるべきではありませんか?... ちょっと、それは素晴らしい質問かもしれません :)

于 2008-10-10T14:55:51.170 に答える
0

クラスに強い制約を課さない限り、この問題には「簡単な」解決策はありません。

たとえば、特定のクラスに複数のコンストラクターを使用している場合、すべてのパラメーターが equals/hash メソッドで適切に考慮されるようにするにはどうすればよいでしょうか? デフォルト値はどうですか?残念ながら、これらはやみくもに自動化することはできません。

于 2008-10-10T06:02:21.727 に答える
0

古い質問に対する新しい回答ですが、2011 年 5 月にGuava (以前の Google Collections) は、多くのボイラープレートを削除した というクラスをリリースしましたEqualsTester。独自のインスタンスを作成する必要がありますが、各オブジェクトをそれ自体、null、等価グループ内のすべてのオブジェクト、他のすべての等価グループ内のすべてのオブジェクト、および何も一致しないはずの秘密のインスタンスと比較します。また、これらすべての組み合わせをa.equals(b)意味するかどうかもチェックします。a.hashCode() == b.hashCode()

Javadoc の例:

new EqualsTester()
   .addEqualityGroup("hello", "h" + "ello")
   .addEqualityGroup("world", "wor" + "ld")
   .addEqualityGroup(2, 1 + 1)
   .testEquals();
于 2012-10-31T05:59:57.223 に答える
0

多分私は質問を誤解している(そしてあまりにもCSである)が、あなたが説明している問題が一般的なケースでは決定可能であるようには聞こえない.

つまり、オーバーライドされたメソッドがすべての入力で同じように機能することを単体テストで保証できる唯一の方法は、すべての入力でそれを試すことです。等しい場合は、すべてのオブジェクトの状態を意味します。

現在のテスト フレームワークが自動的に切り詰めて可能性を抽象化するかどうかはわかりません。

于 2008-10-10T15:41:27.820 に答える