Katakanlah saya memiliki kelas tanpa metode sama dengan (), yang tidak memiliki sumber. Saya ingin menegaskan kesetaraan pada dua contoh kelas itu.
Saya bisa melakukan banyak pernyataan:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
Saya tidak suka solusi ini karena saya tidak mendapatkan gambaran kesetaraan penuh jika pernyataan awal gagal.
Saya dapat membandingkan sendiri secara manual dan melacak hasilnya:
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);
Ini memberi saya gambaran kesetaraan penuh, tetapi kikuk (dan saya bahkan belum memperhitungkan kemungkinan masalah nol). Opsi ketiga adalah menggunakan Comparator, tetapi bandingkanTo () tidak akan memberi tahu saya bidang mana yang gagal persamaan.
Apakah ada praktik yang lebih baik untuk mendapatkan apa yang saya inginkan dari objek, tanpa subclassing dan overridding sama (ugh)?
java
unit-testing
junit
Ryan Nelson
sumber
sumber
equal
metode hanya memberi tahu apakah dua contoh sama, dan kami tidak peduli mengapa intes tidak sama.Object
memilikiequals
metode, yang mungkin Anda maksud tidak ada metode sama yang diganti.Jawaban:
Mockito menawarkan pencocok refleksi:
Untuk versi terbaru penggunaan Mockito:
Untuk versi yang lebih lama gunakan:
sumber
org.mockito.internal.matchers.apachecommons
. Status dokumen Mockito:org.mockito.internal
-> "Kelas internal, tidak untuk digunakan oleh klien." Anda akan membahayakan proyek Anda menggunakan ini. Ini dapat berubah di versi Mockito apa pun. Baca di sini: site.mockito.org/mockito/docs/current/overview-summary.htmlMockito.refEq()
sebagai gantinya.Mockito.refEq()
gagal ketika objek tidak memiliki id set = (refEq
gagal untuk membandingkan karena metode kode hash tidak dapat membandingkan objek.Ada banyak jawaban yang benar di sini, tetapi saya ingin menambahkan versi saya juga. Ini didasarkan pada Assertj.
PEMBARUAN: Dalam assertj v3.13.2 metode ini tidak digunakan lagi seperti yang ditunjukkan oleh Woodz dalam komentar. Rekomendasi saat ini adalah
sumber
usingRecursiveComparison()
denganisEqualTo()
, sehingga barisnya adalahassertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
Saya biasanya menerapkan usecase ini menggunakan org.apache.commons.lang3.builder.EqualsBuilder
sumber
Saya tahu ini agak tua, tapi saya harap ini membantu.
Saya mengalami masalah yang sama dengan Anda, jadi, setelah penyelidikan, saya menemukan beberapa pertanyaan serupa dari yang ini, dan, setelah menemukan solusinya, saya menjawab hal yang sama, karena saya pikir itu bisa membantu orang lain.
Jawaban yang paling banyak dipilih (bukan yang dipilih oleh penulis) untuk pertanyaan serupa ini , adalah solusi yang paling sesuai untuk Anda.
Pada dasarnya, ini terdiri dari penggunaan perpustakaan yang disebut Unitils .
Inilah gunanya:
Yang akan lolos bahkan jika kelas
User
tidak diimplementasikanequals()
. Anda dapat melihat lebih banyak contoh dan pernyataan yang sangat keren disebutassertLenientEquals
dalam tutorial mereka .sumber
Unitils
tampaknya telah mati, lihat stackoverflow.com/questions/34658067/is-unitils-project-alive .Anda dapat menggunakan Apache commons lang ReflectionToStringBuilder
Anda dapat menentukan atribut yang ingin Anda uji satu per satu, atau lebih baik, mengecualikan yang tidak Anda inginkan:
Anda kemudian membandingkan kedua string tersebut seperti biasa. Untuk poin tentang refleksi yang lambat, saya berasumsi ini hanya untuk pengujian, jadi seharusnya tidak terlalu penting.
sumber
Jika Anda menggunakan hamcrest untuk asserts Anda (assertThat) dan tidak ingin menggunakan libs uji tambahan, Anda dapat menggunakan
SamePropertyValuesAs.samePropertyValuesAs
untuk menegaskan item yang tidak memiliki metode sama yang diganti.Keuntungannya adalah Anda tidak perlu menggunakan framework pengujian lain dan ini akan memberikan kesalahan yang berguna saat assert gagal (
expected: field=<value> but was field=<something else>
) daripadaexpected: true but was false
jika Anda menggunakan sesuatu sepertiEqualsBuilder.reflectionEquals()
.Kelemahannya adalah ini adalah perbandingan yang dangkal dan tidak ada opsi untuk mengecualikan bidang (seperti yang ada di EqualsBuilder), jadi Anda harus bekerja di sekitar objek bersarang (misalnya menghapusnya dan membandingkannya secara independen).
Kasus terbaik:
Kasus Jelek:
Jadi, pilih racunmu. Kerangka tambahan (mis. Unitils), kesalahan tidak membantu (mis. EqualsBuilder), atau perbandingan dangkal (hamcrest).
sumber
Library Pencocokan Utilitas Hamcrest 1.3 memiliki pencocokan khusus yang menggunakan refleksi, bukan sama.
sumber
Beberapa metode perbandingan refleksi dangkal
Pilihan lainnya adalah mengubah objek menjadi json dan membandingkan string.
sumber
Menggunakan Shazamcrest , Anda dapat melakukan:
sumber
reflectEquals
mengembalikanfalse
ketika objek memiliki referensi yang berbeda.Bandingkan bidang demi bidang:
sumber
Penegasan AssertJ dapat digunakan untuk membandingkan nilai tanpa
#equals
metode yang diganti dengan benar, misalnya:sumber
Karena pertanyaan ini sudah lama, saya akan menyarankan pendekatan modern lainnya menggunakan JUnit 5.
Dengan JUnit 5, ada sebuah metode yang dipanggil
Assertions.assertAll()
yang akan memungkinkan Anda untuk mengelompokkan semua pernyataan dalam pengujian Anda bersama-sama dan itu akan mengeksekusi masing-masing dan mengeluarkan pernyataan yang gagal di akhir. Ini berarti bahwa pernyataan apa pun yang gagal lebih dulu tidak akan menghentikan eksekusi pernyataan terakhir.sumber
Anda dapat menggunakan refleksi untuk "mengotomatiskan" pengujian kesetaraan penuh. Anda dapat menerapkan kode "pelacakan" persamaan yang Anda tulis untuk satu bidang, kemudian menggunakan refleksi untuk menjalankan pengujian tersebut pada semua bidang di objek.
sumber
Ini adalah metode perbandingan umum, yang membandingkan dua objek dari kelas yang sama untuk nilai-nilainya dari bidangnya (ingatlah bahwa itu dapat diakses dengan metode get)
sumber
Saya menemukan kasus yang sangat mirip.
Saya ingin membandingkan pada tes bahwa obyek memiliki nilai atribut yang sama dengan satu sama lain, tetapi metode seperti
is()
,refEq()
, dll tidak akan bekerja untuk alasan seperti objek saya memiliki nilai null dalam Suratid
atribut.Jadi, inilah solusi yang saya temukan (yah, rekan kerja menemukan):
Jika nilai yang diperoleh
reflectionCompare
adalah 0 berarti sama. Jika -1 atau 1, mereka berbeda pada beberapa atribut.sumber
Dalam kasus umum dengan AssertJ Anda dapat membuat strategi komparator khusus:
Menggunakan strategi perbandingan kustom dalam pernyataan
Contoh AssertJ
sumber
Saya memiliki teka-teki yang sama persis saat menguji unit aplikasi Android, dan solusi termudah yang saya dapatkan adalah menggunakan Gson untuk mengonversi objek nilai aktual dan yang diharapkan menjadi
json
dan membandingkannya sebagai string.Keuntungan dari ini dibandingkan secara manual membandingkan bidang per bidang adalah Anda membandingkan semua bidang Anda, jadi meskipun Anda nanti menambahkan bidang baru ke kelas Anda itu akan diuji secara otomatis, dibandingkan dengan jika Anda menggunakan banyak
assertEquals()
pada semua bidang, yang kemudian perlu diperbarui jika Anda menambahkan lebih banyak bidang ke kelas Anda.jUnit juga menampilkan string untuk Anda sehingga Anda dapat langsung melihat perbedaannya. Tidak yakin seberapa andal pemesanan lapangan
Gson
, itu bisa menjadi masalah potensial.sumber
Saya mencoba semua jawaban dan tidak ada yang berhasil untuk saya.
Jadi saya telah membuat metode saya sendiri yang membandingkan objek java sederhana tanpa masuk jauh ke dalam struktur bersarang ...
Metode mengembalikan nol jika semua bidang cocok atau string berisi detail yang tidak cocok.
Hanya properti yang memiliki metode pengambil yang dibandingkan.
Cara Penggunaan
Contoh keluaran jika ada ketidakcocokan
Output menunjukkan nama properti dan nilai masing-masing dari objek yang dibandingkan
Kode (Java 8 dan lebih tinggi):
sumber
Sebagai alternatif untuk junit-only, Anda dapat menyetel kolom ke null sebelum sama dengan pernyataan:
sumber
Dapatkah Anda memasukkan kode perbandingan yang Anda posting ke dalam beberapa metode utilitas statis?
Kemudian Anda dapat menggunakan metode ini di JUnit seperti ini:
assertEquals ("Objek tidak sama", "", findDifferences (obj1, obj));
yang tidak kikuk dan memberi Anda informasi lengkap tentang perbedaan, jika ada (tidak persis dalam bentuk assertEqual normal tetapi Anda mendapatkan semua info sehingga seharusnya bagus).
sumber
Ini tidak akan membantu OP, tetapi mungkin membantu pengembang C # yang berakhir di sini ...
Seperti yang diposting Enrique , Anda harus mengganti metode sama dengan.
Saran saya adalah tidak menggunakan subclass. Gunakan kelas parsial.
Partial Class Definitions (MSDN)
Jadi kelas Anda akan terlihat seperti ...
Untuk Java, saya setuju dengan saran untuk menggunakan refleksi. Ingatlah bahwa Anda harus menghindari penggunaan refleksi bila memungkinkan. Proses ini lambat, sulit untuk di-debug, dan bahkan lebih sulit untuk dipertahankan di masa mendatang karena IDE dapat merusak kode Anda dengan melakukan penggantian nama bidang atau semacamnya. Hati-hati!
sumber
Dari komentar Anda hingga jawaban lain, saya tidak mengerti apa yang Anda inginkan.
Hanya demi diskusi, katakanlah bahwa kelas tersebut mengganti metode sama dengan.
Jadi UT Anda akan terlihat seperti ini:
Dan Anda selesai. Selain itu, Anda tidak bisa mendapatkan "gambaran kesetaraan penuh" jika pernyataan gagal.
Dari apa yang saya pahami, Anda mengatakan bahwa meskipun jenisnya menimpa sama, Anda tidak akan tertarik padanya, karena Anda ingin mendapatkan "gambaran kesetaraan penuh". Jadi tidak ada gunanya memperpanjang dan menimpa yang sama.
Jadi, Anda harus memilih: membandingkan properti dengan properti, menggunakan refleksi atau pemeriksaan hard-code, saya sarankan yang terakhir. Atau: bandingkan representasi yang dapat dibaca manusia dari objek-objek ini.
Misalnya, Anda bisa membuat kelas helper yang membuat serial jenis yang ingin Anda bandingkan dengan dokumen XML dan kemudian membandingkan XML yang dihasilkan! dalam hal ini, Anda dapat melihat secara visual apa yang sebenarnya sama dan apa yang tidak.
Pendekatan ini akan memberi Anda kesempatan untuk melihat gambaran lengkapnya tetapi juga relatif rumit (dan pada awalnya sedikit rawan kesalahan).
sumber
Anda dapat mengganti metode sama dengan kelas seperti:
Nah, jika Anda ingin membandingkan dua objek dari kelas, Anda harus menerapkan metode kode hash dan sama dengan cara tertentu
sumber