Junit4: Memperkenalkan hierarki BiMatcher

Dibuat pada 8 Feb 2018  ·  9Komentar  ·  Sumber: junit-team/junit4

Fitur yang bagus akan memperkenalkan hierarki BiMatcher (analog dari org.hamcrest.Matcher , tetapi menggunakan 2 argumen). Atau standar Comparator dapat digunakan untuk tujuan ini. Juga BiPredicate dapat digunakan (ini akan mengikat JUnit ke Java-8, tetapi akan menambahkan logika AND/ATAU/NOT yang sudah ada).
Beberapa catatan untuk semua kode lebih lanjut:

  • BiMatcher , BiPredicate dan Comparator nama akan digunakan secara bergantian.
  • Semua kode tidak final dan hanya ide umum.

Metode utama untuk menambahkan kelas Assert :

  • assertThat(T expected, T actual, Comparator<T> biMatcher);
  • assertThat(String message, T expected, T actual, Comparator<T> biMatcher); (mungkin tidak perlu, lihat di bawah).
  • Beberapa metode assertArray() (lihat di bawah).

Motivasinya: terkadang Anda perlu melakukan banyak pemeriksaan serupa terhadap sekumpulan objek. Fungsionalitas yang ada memungkinkan, tetapi dengan banyak kode tambahan (loop dan kondisi). Dengan Comparator itu dapat dilakukan dengan lebih sedikit kode dan dengan fleksibilitas yang lebih tinggi.

Contoh nyata (dari mana saya benar-benar mulai memikirkan fitur ini): perlu menguji semua objek dalam array sama atau tidak sama (tergantung pada flag boolean).

Dengan kemampuan JUnit saat ini akan terlihat seperti:
singkat:

for (int i = 0; i < elements.length - 1; i++) {
  if (checkSame) { // Same
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  } else { // Not same
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

kinerja yang lebih baik (tetapi siapa yang peduli dengan kinerja dalam tes):

if (checkSame) { // Same
  for (int i = 0; i < elements.length - 1; i++) {
    assertSame("elements must be the same.", elements[i], elements[i + 1]);
  }
else { // Not same
  for (int i = 0; i < elements.length - 1; i++) {
    assertNotSame("elements must be not the same.", elements[i], elements[i + 1]);
  }
}

Kita juga dapat mengimplementasikan Comparator dan menggunakan assertTrue()/assertFalse() , tetapi kode untuk membuat komparator juga akan besar (kecuali kita menggunakan lambdas).

Dengan kode pendekatan baru akan terlihat jauh lebih pendek dan lebih bersih bagi saya, seperti ini:

Comparator<T> comparator = checkSame ? BiMatchers.same() : BiMatchers.notSame();
String message = checkSame ? "elements must be the same." : "elements must be not the same.";
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Untuk membuatnya lebih pendek, kita dapat memperluas Comparator ke MessagedComparator dengan properti message opsional, jadi JUnit akan mengambilnya dari sana. Seperti ini:

MessagedComparator<T> comparator = checkSame ? BiMatchers.same("elements must be the same.") : BiMatchers.notSame("elements must be not the same.");
for (int i = 0; i < elements.length - 1; i++) {
  assertThat(message, elements[i], elements[i + 1], comparator);
}

Konsekuensinya sangat luas:
1) Kelas Assert akan sangat fleksibel secara umum, karena Anda dapat menggunakan pembanding standar atau sendiri tanpa banyak kode.
2) Sebagai hasil dari sebelumnya, lambdas dapat digunakan lebih mudah untuk menyuntikkan kondisi apa pun.
3) Kaskade logika tambahan (DAN, ATAU, BUKAN) dapat ditambahkan di luar kotak (sesuatu yang mirip dengan org.hamcrest.CoreMatchers ). Saat ini untuk setiap fitur mini baru diperlukan metode baru, misalnya assertNotSame() sebelah assertSame() dll. Atau lagi kita membutuhkan metode assertTrue()/assertFalse() .
4) Seluruh kelas Assert dapat difaktorkan ulang ke bentuk terpadu. Hanya satu contoh:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(message, expected, actual, BiMatchers.same())
}

public static void assertThat(String message, T expected, T actual, Comparator<T> biMatcher) {
...
}

atau seperti yang sudah disebutkan:

public static void assertSame(String message, Object expected, Object actual) {
  assertThat(expected, actual, BiMatchers.same(message))
}

public static void assertThat(T expected, T actual, MessagedComparator<T> biMatcher) {
...
}

5) assertArray() metode dapat ditambahkan (dengan demikian metode lama refactored). Misalnya:

public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) {
  assertArray(expecteds, actuals, BiMatchers.equals());
}

public static void assertArray(boolean[] expecteds, boolean[] actuals, Comparator<Boolean>) {
...
}

Jadi misalnya Anda dapat memeriksa semua elemen dalam 2 array sama semudah:

Assert.assertArray(array1, array2, BiMatchers.same());

Juga panjang array atau pemeriksaan lainnya dapat dikontrol secara terpisah. Kode semu:

Assert.assertArray(array1, array2, and(sameLength(), same()));

Semua 9 komentar

Terima kasih telah mengangkat masalah ini.

Saya lebih suka bahwa JUnit 4.x tidak menambahkan lebih banyak DSL pernyataan. Sangat sulit untuk mendapatkan DSL yang benar dan fleksibel, dan saya tidak yakin masuk akal untuk menghabiskan waktu dan upaya untuk itu di JUnit ketika ada kerangka kerja pernyataan pihak ketiga yang bagus seperti Truth atau Fest.

Juga, fitur yang membutuhkan Java 8 harus pergi ke http://github.com/junit-team/junit5

@gitIvanB Terima kasih telah membuka masalah ini. Seperti @kcooney , saya juga berpikir ini sebaiknya ditangani oleh perpustakaan pernyataan, misalnya AssertJ.

@kcooney , @marcphilipp , terima kasih atas petunjuknya. Sepertinya penggunaan lib pernyataan adalah praktik terbaik di sini.
Satu pertanyaan tambahan. Dapatkah saya menggunakan sebagai aturan praktis bahwa penggunaan Assert tidak digunakan lagi (atau tidak disarankan)? Terutama mengingat kemungkinan peningkatan di masa mendatang dari JUnit-4 ke JUnit-5.

@gitIvanB Pertanyaannya agak tidak jelas. Jika mengembangkan melawan junit4 seseorang menggunakan org.junit.Assert , jika mengembangkan melawan junit5 maka org.junit.jupiter.api.Assertions

Pendekatan yang disarankan adalah mengimpor metode secara statis darinya, untuk menghindari Assert. di setiap baris.

@gitIvanB Anda seharusnya tidak menggunakan junit.framework.Assert , tapi org.junit.Assert baik-baik saja. Saat Anda melakukan peningkatan, Anda dapat menggunakan IDE untuk mengonversi pernyataan JUnit 4 ke JUnit Jupiter (IDEA sudah mendukungnya). Perbedaan terbesar adalah bahwa parameter pesan opsional datang pertama di JUnit 4 tetapi terakhir di Jupiter. Atau, Anda dapat memutuskan untuk menggunakan pustaka pernyataan yang berbeda sekarang dan tetap menggunakannya saat bermigrasi dari Vintage ke Jupiter.

@panchenko , @marcphilipp Jadi seperti yang saya pahami, org.junit.Assert JUnit-4 disegel dan tidak akan diperkaya dengan metode baru. Di JUnit-5 saya perlu menggunakan org.junit.jupiter.api.Assertions (sebagai pengganti org.junit.Assert ) atau beberapa lib pernyataan.
Saya perlu beberapa waktu untuk mempelajari JUnit-5, tetapi dari pandangan pertama ke org.junit.jupiter.api.Assertions sepertinya pendekatannya secara umum mirip dengan org.junit.Assert . Jadi ini adalah peluang besar bahwa saya perlu membuat tiket serupa untuk JUnit-5 :) Saya percaya JUnit-5 harus memberikan pernyataan yang lengkap atau sepenuhnya mendelegasikan ke lib pernyataan.

Filosofi @gitIvanB JUnit adalah menyediakan kerangka kerja yang baik dan dapat diperluas untuk menulis tes untuk Java di Jawa. Menjadi kerangka kerja yang dapat diperluas, kami sering melihat proyek sumber terbuka lainnya memperluas kerangka kerja dan/atau menyediakan pustaka pengujian yang kaya yang dapat digunakan dengan JUnit.

Untuk asersi, ada beberapa proyek yang menyediakan kumpulan asersi yang lebih kaya, terkadang dengan cara yang dapat diperluas.
Misalnya, ada Google Truth (https://github.com/google/truth), FEST (https://github.com/alexruiz/fest-assert-2.x), AssertJ (http://joel- costigliola.github.io/assertj/) dan Hamcrest (http://hamcrest.org/JavaHamcrest/).

Karena ada begitu banyak pustaka pernyataan yang luar biasa di luar sana, saya enggan menerima permintaan fitur baru untuk org.junit.Assert . Saya tidak akan menganggapnya beku (meskipun saya akan mempertimbangkan junit.framework.Assert beku). Faktanya, 4.13 akan memperkenalkan assertThrows . Tetapi karena kita tidak akan pernah memiliki serangkaian pernyataan yang kaya seperti proyek-proyek itu, kita merasa nyaman memberikan dasar-dasarnya.

Dengan kata lain, komunitas sehat telah terbentuk di sekitar penggunaan dan pemeliharaan proyek-proyek itu, jadi saya pikir kita harus merangkul dan mendukung mereka.

Saya tidak dapat berbicara untuk JUnit5, tetapi saya membayangkan pengembang asli merasa mereka tidak dapat merilis JUnit generasi berikutnya tanpa dasar yang baik dari metode pernyataan (atau mungkin mereka merasa seperti cara terbaik untuk memastikan bahwa kerangka kerja baru berfungsi dan dipoles adalah untuk menguji JUnit5 menggunakan JUnit5). Praktik pemrograman baru menyebabkan mereka membuat keputusan yang berbeda tentang seperti apa tampilan API pernyataan dasar daripada yang dilakukan Kent, Erich, dan David, jadi Anda akan melihat beberapa perbedaan. Tetapi Anda mungkin tidak akan pernah melihat di JUnit sekaya serangkaian pernyataan seperti Hamcrest atau DSL yang dapat diperluas seperti Truth.

Saya menyerahkannya kepada tim JUnit5 untuk memutuskan jenis perubahan apa yang akan mereka pertimbangkan. Jika Anda merasa kuat bahwa
metode yang Anda usulkan penting sebagai dasar penulisan tes yang baik, jangan ragu untuk membuat masalah di sana.

Ketika kami mulai mengerjakan JUnit 5 (dengan nama kode "JUnit Lambda" pada saat itu), kami mendiskusikan cakupan dari apa yang ingin kami capai. Menulis perpustakaan Assertion jenis baru secara eksplisit diputuskan untuk tidak berada dalam ruang lingkup.

Atau, seperti yang dikatakan oleh Panduan Pengguna JUnit 5 :

Meskipun fasilitas penegasan yang disediakan oleh JUnit Jupiter cukup untuk banyak skenario pengujian, ada kalanya lebih banyak daya dan fungsionalitas tambahan seperti korek api diinginkan atau diperlukan. Dalam kasus seperti itu, tim JUnit merekomendasikan penggunaan pustaka pernyataan pihak ketiga seperti AssertJ, Hamcrest, Truth, dll. Oleh karena itu, pengembang bebas menggunakan pustaka pernyataan pilihan mereka.

Jadi, ini juga tidak dibekukan, tetapi tujuannya sama seperti di JUnit 4, yaitu untuk memberikan serangkaian pernyataan dasar untuk memulai pengguna. Kami bahkan menggunakan AssertJ untuk pengujian unit kami sendiri.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat