Apakah metode assertEquals Java dapat diandalkan?


199

Saya tahu ==ada beberapa masalah saat membandingkan dua Strings. Tampaknya itu String.equals()adalah pendekatan yang lebih baik. Yah, saya sedang melakukan pengujian JUnit dan kecenderungan saya adalah untuk digunakan assertEquals(str1, str2). Apakah ini cara yang dapat diandalkan untuk menyatakan dua String berisi konten yang sama? Saya akan menggunakan assertTrue(str1.equals(str2)), tetapi kemudian Anda tidak mendapatkan manfaat dari melihat apa yang diharapkan dan nilai aktual pada kegagalan.

Pada catatan terkait, apakah ada orang yang memiliki tautan ke halaman atau utas yang menjelaskan masalah dengan jelas str1 == str2?


1
Jika Anda tidak yakin, Anda dapat membaca kodenya, atau Javadoc. BTW jika Anda ingin menguji mereka adalah objek yang sama Anda dapat menggunakan assertSame.
Peter Lawrey

2
Jika str1 dan str2 adalah null, assertEquals () benar, tetapi assertTrue (str1.equals (str2)) melempar pengecualian. Contoh pertama juga akan mencetak pesan kesalahan yang berguna seperti isi str1 dan str2, yang kedua tidak.
Peter Lawrey

Jawaban:


274

Anda harus selalu menggunakan .equals()ketika membandingkan Stringsdi Jawa.

JUnit memanggil .equals()metode untuk menentukan kesetaraan dalam metode assertEquals(Object o1, Object o2).

Jadi, Anda pasti aman menggunakannya assertEquals(string1, string2). (Karena Strings adalah Objects)

Berikut ini tautan ke pertanyaan Stackoverflow yang hebat mengenai beberapa perbedaan antara ==dan .equals().


12
IIRC assertEquals () berhasil jika kedua string adalah nol. Jika ini bukan yang Anda inginkan, panggil assertNotNull () juga.
finnw

10
Selain itu, jika Anda ingin menguji untuk ==, Anda dapat memanggil assertSame ()
james

7
Saya tidak akan mengatakan selalu ; kadang-kadang referensi kesetaraan diinginkan, bahkan untuk string.
Karu

30

assertEqualsmenggunakan equalsmetode untuk perbandingan. Ada pernyataan berbeda assertSame,, yang menggunakan ==operator.

Untuk memahami mengapa ==tidak boleh digunakan dengan string, Anda perlu memahami apa yang ==dilakukan: string melakukan pengecekan identitas. Artinya, a == bperiksa untuk melihat apakah adan bmerujuk ke objek yang sama . Itu dibangun ke dalam bahasa, dan perilakunya tidak dapat diubah oleh kelas yang berbeda. The equalsmetode, di sisi lain, dapat ditimpa oleh kelas. Sementara perilaku default-nya (di Objectkelas) adalah melakukan pemeriksaan identitas menggunakan ==operator, banyak kelas, termasuk String, menimpanya untuk melakukan pemeriksaan "ekivalensi". Dalam hal String, alih-alih memeriksa jika adan bmerujuk ke objek yang sama,a.equals(b) memeriksa untuk melihat apakah objek yang mereka rujuk adalah kedua string yang berisi karakter yang persis sama.

Waktu analogi: bayangkan bahwa setiap Stringobjek adalah selembar kertas dengan sesuatu yang tertulis di atasnya. Katakanlah saya memiliki dua lembar kertas dengan "Foo" tertulis di atasnya, dan satu lagi dengan "Bar" tertulis di atasnya. Jika saya mengambil dua lembar kertas pertama dan menggunakannya ==untuk membandingkannya, kertas itu akan kembali falsekarena pada dasarnya menanyakan "apakah ini kertas yang sama?". Bahkan tidak perlu melihat apa yang tertulis di kertas. Fakta bahwa saya memberikannya dua lembar kertas (bukan yang sama dua kali) berarti kertas itu akan kembali false. equalsNamun, jika saya menggunakan , equalsmetode ini akan membaca dua lembar kertas dan melihat bahwa mereka mengatakan hal yang sama ("Foo"), dan itu akan kembali true.

Bit yang membingungkan dengan Strings adalah bahwa Java memiliki konsep "interning" Strings, dan ini (efektif) secara otomatis dilakukan pada string literal dalam kode Anda. Ini berarti bahwa jika Anda memiliki dua string literal yang setara dalam kode Anda (bahkan jika mereka berada di kelas yang berbeda) mereka sebenarnya akan merujuk ke Stringobjek yang sama . Ini membuat ==operator kembali truelebih sering daripada yang diharapkan.


"Yaitu, a == b memeriksa untuk melihat apakah a dan b adalah objek yang sama." Secara teknis ia memeriksa apakah a dan b merujuk ke objek yang sama, karena a dan b adalah referensi. Kecuali saya sangat salah.
bob

@ user1903064 itu benar. Karena variabel non-primitif hanya dapat berisi referensi di Jawa, itu biasa untuk melewati tingkat tipuan ekstra ketika berbicara tentang mereka, tetapi saya setuju bahwa dalam kasus ini menjadi lebih eksplisit bermanfaat. Saya sudah memperbarui jawabannya. Terima kasih untuk sarannya!
Laurence Gonsalves

7

Singkatnya - Anda dapat memiliki dua objek String yang berisi karakter yang sama tetapi objek yang berbeda (di lokasi memori yang berbeda). Operator == memeriksa untuk melihat bahwa dua referensi menunjuk ke objek yang sama (lokasi memori), tetapi metode equals () memeriksa apakah karakternya sama.

Biasanya Anda tertarik untuk memeriksa apakah dua String berisi karakter yang sama, bukan apakah mereka menunjuk ke lokasi memori yang sama.


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

Ya, ini digunakan sepanjang waktu untuk pengujian. Sangat mungkin bahwa kerangka kerja pengujian menggunakan .equals () untuk perbandingan seperti ini.

Di bawah ini adalah tautan yang menjelaskan "kesalahan kesetaraan string". Intinya, string di Jawa adalah objek, dan ketika Anda membandingkan kesetaraan objek, biasanya string itu didasarkan pada alamat memori, dan bukan berdasarkan konten. Karena itu, dua string tidak akan menempati alamat yang sama, bahkan jika kontennya identik, sehingga tidak akan cocok dengan benar, meskipun mereka terlihat sama ketika dicetak.

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


3

JUnit assertEquals(obj1, obj2)memang memanggil obj1.equals(obj2).

Ada juga assertSame(obj1, obj2)yang tidak obj1 == obj2(yaitu, memverifikasi itu obj1dan obj2merujuk contoh yang sama ), yang adalah apa yang Anda coba hindari.

Jadi kamu baik-baik saja.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.