4

assertEqualsテストクラスでは、に依存しない特別なロジックを使用して、独自のオーバーロードを提供したいと思いObject.equalsます。残念ながら、assertEqualsローカルでメソッドを宣言するとすぐにJavaが静的インポートを検出しなくなるため、これは機能しませんorg.junit.Assert.*

これを回避する方法はありますか?つまり、静的にインポートされたメソッドに追加のオーバーロードを提供する方法はありますか?(かなり明白な解決策は、メソッドに別の名前を付けることですが、この解決策は同じ美的魅力を持っていません。)

私のテストクラスファイルは次のようになります。

package org.foo.bar;

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {
    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        assertEquals(42, a.getFoo()); // Error *
    }

    @Test
    public void testCopyConstructor() throws Exception {
        Bar a = new Bar();
        // Fill a.
        Bar b = new Bar(a);
        assertEquals(a, b);
    }
}

Error *は「assertEquals(Bar, Bar)型のメソッドBarTestは引数には適用できません(int, int)。」</p>

4

4 に答える 4

3

この回答には 2 つのセクションがあります。1 つはコンパイル エラーに関するもので、もう 1 つは assertEquals() の使用に関するものです。

問題は、2 つの異なる名前空間に 2 つの assertEquals() メソッドがあることです。1 つは org.junit.Assert 名前空間に存在し、もう 1 つは org.foo.bar.BarTest 名前空間 (現在の名前空間) にあります。

このエラーは、Java 言語仕様で宣言されているシャドーイング ルールにより、コンパイラによって報告されます。Assert.assertEquals() の静的インポートは、BarTest クラスで宣言された assertEquals() によって隠されています。

修正 (シャドウ宣言の場合は常に) は、FQN (完全修飾名) を使用することです。JUnit Assert クラスの assertEquals(...) を使用する場合は、

org.junit.Assert.assertEquals(...)

宣言を使用する必要がある場合は、単に使用します

assertEquals(...)

シャドウされている BarTest のみ。Assert.assertEquals() または BarTest.asserEquals() のいずれかのみを必要とする他のすべてのクラスでは、Assert または BarTest をインポートできます (他の場所で BarTest をインポートする必要はないと思いますが、それでも述べています)。

シャドウイングがない場合は、クラスまたは静的メソッドを単純にインポートして、FQN なしで使用する余裕があります。

追加の考慮事項

Assert.assertEquals() は、引数のクラスの equals() メソッドを内部的に利用します。テスト ケースで assertEquals() を宣言すると、DRY 原則に違反します。型の equals() メソッドを実装して一貫して使用する必要があるためです。ソース コードと単体テストに 2 つの異なる実装を配置すると、混乱が生じる可能性があります。

最善の方法は、Bar に equals() を実装してから、テスト ケースで Assert.assertEquals() を使用することです。すでに持っている場合は、BarTest.assertEquals() は必要ありません。assertEquals() の擬似コードは次のようになります。

  1. 両方の引数が null の場合は、true を返します。
  2. expectedが null でない場合は、 expectedで equals() を呼び出し、引数として実際の値を渡します。オブジェクトが等しい場合は true を返します。
  3. オブジェクトが等しくない場合は、フォーマットされたメッセージで AssertionError をスローします。
于 2009-09-19T15:26:49.200 に答える
3

assertEquals(Bar, Bar)単体テストでの呼び出しの特定の例に対する考えられる解決策の1 つは、次のように、静的メソッドを提供するクラスでクラスを拡張することです。

class BarAssert extends Assert {
  public static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }
}

import static BarAssert.assertEquals;その後、カスタム ロジックを含めて使用できます。

これは質問に直接答えるものではなく、あなたの例をより対象としていることをお詫びします。質問に添付された私のコメントによると、このアプローチに反対することをお勧めします。

于 2009-09-19T15:38:39.553 に答える
1

唯一の方法は、どちらか一方を完全に修飾することです。

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {

    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        org.junit.Assert.assertEquals(42, a.getFoo());
    }
}
于 2009-09-19T15:23:41.967 に答える
0
this.assertEquals(a,b);

また

BarTest.assertEquals(a,b);

最初のメソッドを使用します。静的メソッドであるにもかかわらず、それを使用するにはインスタンスが必要であり(プライベート)、this将来の名前変更の気まぐれの影響を受けないためです。

于 2009-09-19T15:53:00.793 に答える