JavaのassertEqualsメソッドは信頼できますか?


199

==2つを比較すると、いくつかの問題があることがわかりStringsます。それString.equals()はより良いアプローチのようです。さて、私はJUnitテストを行っており、私の傾向はを使用することassertEquals(str1, str2)です。これは、2つの文字列に同じコンテンツが含まれていることをアサートする信頼できる方法ですか?私はを使用しassertTrue(str1.equals(str2))ますが、失敗した場合の期待値と実際の値を確認するメリットはありません。

関連するノートでは、誰もが問題を明確に説明しているページまたはスレッドへのリンクを持っていますかstr1 == str2


1
不明な場合は、コードまたはJavadocを参照してください。ところで、それらをテストしたい場合は、assertSameを使用して同じオブジェクトを使用できます。
Peter Lawrey、

2
str1とstr2がnullの場合、assertEquals()はtrueですが、assertTrue(str1.equals(str2))は例外をスローします。最初の例では、str1とstr2の内容などの有用なエラーメッセージも出力されますが、2番目の例では出力されません。
Peter Lawrey、2010年

回答:


274

Javaで比較する場合は常に使用する必要があります。.equals()Strings

JUnitは.equals()メソッドを呼び出して、メソッドの等価性を判断しassertEquals(Object o1, Object o2)ます。

したがって、あなたは間違いなくを使用して安全assertEquals(string1, string2)です。(StringsはObjectsであるため)

ここでは素晴らしいstackoverflowの質問へのリンクであるとの相違点のいくつかについて==とは.equals()


12
IIRC assertEquals()は、両方の文字列がnullの場合に成功します。これが必要なものでない場合は、assertNotNull()も呼び出します。
finnw 2009

10
さらに、==をテストする場合は、assertSame()を呼び出すことができます
james

7
いつも言っているわけではない。文字列であっても、参照の等価性が必要な場合があります。
Karu

30

assertEqualsequals比較にメソッドを使用します。演算子assertSameを使用する別のアサートがあり==ます。

==文字列で使用してはいけない理由を理解==するには、何を行うかを理解する必要があります。これは、IDチェックを実行します。つまり、同じオブジェクトを参照しているa == bかどうかを確認します。これは言語に組み込まれており、その動作は異なるクラスによって変更できません。この方法は、他の一方で、クラスによってオーバーライドすることができます。(クラス内の)デフォルトの動作は演算子を使用してIDチェックを実行することですが、などの多くのクラスはそれをオーバーライドして、代わりに「同等」チェックを実行します。の場合、同じオブジェクトをチェックして参照する代わりに、abequalsObject==StringStringaba.equals(b) それらが参照するオブジェクトが両方ともまったく同じ文字を含む文字列であるかどうかを確認します。

類推時間:各Stringオブジェクトが何かが書かれた一枚の紙であると想像してください。「Foo」と書かれた紙と「Bar」と書かれた紙があるとします。最初の2枚の紙を取り、==それらを比較するために使用すると、false本質的に「これらは同じ紙であるか?」と尋ねられるため、結果は戻ります。紙に書かれていることを見る必要さえありません。(同じものを2回ではなく)2枚の紙を渡すという事実は、それが戻ることを意味しますfalseequalsただし、を使用すると、equalsメソッドは2枚の紙を読み取り、同じこと( "Foo")を言っていることがわかり、が返されtrueます。

文字列と混同されるビットは、Javaに文字列の「インターン」の概念があり、これがコード内の文字列リテラルに対して(効果的に)自動的に実行されることです。つまり、コードに2つの同等の文字列リテラルがある場合(それらが異なるクラスにある場合でも)、実際には両方とも同じStringオブジェクトを参照します。これにより、==オペレーターtrueは予想よりも頻繁に戻ります。


「つまり、a == bは、aとbが同じオブジェクトであるかどうかを確認します。」技術的には、aとbが参照であるため、aとbが同じオブジェクトを参照しているかどうかをチェックします。私が非常に間違っていない限り。
ボブ

@ user1903064正解です。非プリミティブ変数はJavaでの参照のみを含むことができるため、それらについて話すとき、間接レベルの余分なレベルをスキップするのが一般的ですが、この場合は、より明示的であることが有益であることに同意します。答えを更新しました。提案をありがとう!
ローレンスゴンサルベス2015年

7

簡単に言えば、同じ文字を含むが異なるオブジェクト(異なるメモリロケーション)である2つのStringオブジェクトを持つことができます。==演算子は、2つの参照が同じオブジェクト(メモリの場所)を指していることを確認しますが、equals()メソッドは文字が同じかどうかを確認します。

通常、2つの文字列に同じ文字が含まれているかどうかを確認する必要があります。同じメモリ位置を指しているかどうかは確認しません。


4
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}

3

はい、常にテストに使用されます。テストフレームワークは、このような比較に.equals()を使用する可能性が非常に高いです。

以下は、「文字列の等価の誤り」を説明するリンクです。基本的に、Javaの文字列はオブジェクトであり、オブジェクトの等価性を比較する場合、通常はコンテンツではなくメモリアドレスに基づいて比較されます。このため、2つの文字列は、たとえ内容が同じであっても、同じアドレスを占めることはないため、印刷時に同じように見えても、正しく一致しません。

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/


3

JUnit assertEquals(obj1, obj2)は実際にを呼び出しますobj1.equals(obj2)

ありますassertSame(obj1, obj2)これはないobj1 == obj2(すなわち、検証obj1およびobj2参照されている同じインスタンスを)あなたは避けるようにしようとしているものです。

だからあなたは大丈夫です。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.