Pencocokan Berisi Hamcrest

Dokumentasi Hamcrest 1.3 Javadoc untuk kelas Matchers menambahkan lebih banyak dokumentasi untuk beberapa metode kelas itu daripada yang tersedia di Hamcrest 1.2. Misalnya, empat metode overloaded berisi memiliki dokumentasi Javadoc yang lebih deskriptif seperti yang ditunjukkan dalam dua cuplikan layar perbandingan yang ditampilkan berikutnya.

Meskipun seseorang dapat mengetahui bagaimana matcher "berisi" bekerja hanya dengan mencobanya, Javadoc di Hamcrest 1.3 membuatnya lebih mudah untuk membaca cara kerjanya. Sebagian besar pengembang Java mungkin memikirkan perilaku seperti String.contains (CharSequence) atau Collection.contains (Object) ketika mereka memikirkan contains()metode. Dengan kata lain, sebagian besar pengembang Java mungkin menganggap "berisi" sebagai penjelasan jika String / Collection berisi karakter / objek yang disediakan di antara karakter / objek lain yang memungkinkan. Namun, untuk pencocokan Hamcrest, "berisi" memiliki arti yang jauh lebih spesifik. Karena dokumentasi Hamcrest 1.3 membuatnya lebih jelas, pencocokan "berisi" jauh lebih sensitif terhadap jumlah item dan urutan item yang diteruskan ke metode ini.

Contoh saya yang ditampilkan di sini menggunakan JUnit dan Hamcrest. Penting untuk ditekankan di sini bahwa file JAR Hamcrest harus muncul pada jalur kelas pengujian unit sebelum file JAR JUnit atau saya harus menggunakan file JUnit JAR "khusus" yang dibuat untuk digunakan dengan Hamcrest JAR yang berdiri sendiri. Menggunakan salah satu pendekatan ini menghindari NoSuchMethodError dan error lainnya (suc as org.hamcrest.Matcher.describeMismatch error) yang dihasilkan dari versi kelas yang tidak cocok. Saya telah menulis tentang nuansa JUnit / Hamcrest ini di postingan blog Moving Beyond Core Hamcrest di JUnit.

Dua cuplikan layar berikutnya menunjukkan hasil (seperti yang ditunjukkan di NetBeans 7.3) dari cuplikan kode pengujian unit yang saya tunjukkan nanti di blog untuk mendemonstrasikan Hamcrest yang berisi matcher. Tes tersebut seharusnya memiliki beberapa kegagalan (7 tes lulus dan 4 tes gagal) untuk memperjelas di mana pencocok Hamcrest mungkin tidak bekerja seperti yang diharapkan tanpa membaca Javadoc. Gambar pertama hanya menampilkan 5 pengujian yang berhasil, 2 pengujian gagal, dan 4 pengujian yang menyebabkan error. Ini karena saya memiliki JUnit yang terdaftar sebelum Hamcrest di jalur kelas "Test Libraries" pada proyek NetBeans. Gambar kedua menunjukkan hasil yang diharapkan karena Hamcrest JAR muncul sebelum JUnit JAR di classpath "Test Libaries" project.

Untuk keperluan demonstrasi ini, saya memiliki kelas yang dibuat-buat sederhana untuk diuji. Kode sumber untuk Mainkelas itu ditampilkan berikutnya.

Main.java

package dustin.examples; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Main class to be unit tested. * * @author Dustin */ public class Main { /** Uses Java 7's diamond operator. */ private Set strings = new HashSet(); public Main() {} public boolean addString(final String newString) { return this.strings.add(newString); } public Set getStrings() { return Collections.unmodifiableSet(this.strings); } } 

Dengan kelas yang akan diuji ditampilkan, sekarang saatnya untuk membangun beberapa pengujian berbasis JUnit dengan pencocok Hamcrest. Secara khusus, pengujian ini untuk memastikan bahwa String yang ditambahkan melalui metode kelas addString(String)ada di dasarnya Setdan dapat diakses melalui getStrings()metode tersebut. Metode pengujian unit yang ditampilkan selanjutnya menunjukkan cara menggunakan pencocok Hamcrest dengan tepat untuk menentukan apakah String yang ditambahkan terdapat dalam class yang mendasari.Set

Menggunakan Hamcrest berisi () Matcher dengan Single String di Set Works

 /** * This test will pass because there is only a single String and so it will * contain that single String and order will be correct by implication. */ @Test public void testAddStringAndGetStringsWithContainsForSingleStringSoWorks() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final Set strings = subject.getStrings(); assertThat(strings, contains("Java")); } 

Pengujian unit yang ditunjukkan di atas berhasil karena Sethanya memiliki satu String di dalamnya sehingga urutan dan jumlah String yang diuji dengan containspencocokan cocok.

Menggunakan Hamcrest Berisi dengan Jumlah Elemen yang Sama Bekerja jika Pesanan Cocok

 /** * The "contains" matcher expects exact ordering, which really means it should * not be used in conjunction with {@code Set}s. Typically, either this method * will work and the method with same name and "2" on end will not work or * vice versa. */ @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks1() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, contains("Java", "Groovy")); } /** * The "contains" matcher expects exact ordering, which really means it should * not be used in conjunction with {@code Set}s. Typically, either this method * will work and the method with same name and "1" on end will not work or * vice versa. */ @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks2() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, contains("Groovy", "Java")); } 

Dua contoh pengujian unit yang ditunjukkan di atas dan output yang dihasilkan dari menjalankan pengujian tersebut seperti yang ditunjukkan di cuplikan layar sebelumnya menunjukkan bahwa selama jumlah argumen ke contains()matcher sama dengan jumlah String dalam koleksi yang sedang diuji, kecocokan dapat berfungsi jika elemen yang diuji memiliki urutan yang sama persis dengan elemen dalam koleksi. Dengan unordered Set, urutan ini tidak dapat diandalkan, jadi contains()kemungkinan besar tidak cocok untuk digunakan dengan pengujian unit pada Setlebih dari satu elemen.

Menggunakan Hamcrest yang Berisi dengan Jumlah Elemen Berbeda Tidak Pernah Berfungsi

 /** * Demonstrate that contains will NOT pass when there is a different number * of elements asked about contains than in the collection. */ @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements1() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, contains("Java")); } /** * Demonstrate that contains will NOT pass when there is a different number * of elements asked about contains than in the collection even when in * different order. */ @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements2() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, contains("Groovy")); } 

Seperti yang ditunjukkan oleh hasil pengujian JUnit, kedua pengujian unit ini tidak pernah lulus karena jumlah elemen yang diuji di dalam Setlebih sedikit daripada jumlah elemen di Set. Dengan kata lain, ini membuktikan bahwa contains()matcher tidak hanya menguji elemen tertentu yang ada dalam sebuah koleksi: ia menguji semua elemen tertentu yang ada dan dalam urutan yang ditentukan. Ini mungkin terlalu membatasi dalam beberapa kasus, jadi sekarang saya akan beralih ke beberapa pertandingan lain yang disediakan Hamcrest untuk menentukan apakah suatu elemen terdapat dalam koleksi tertentu.

Menggunakan Matcher containsInAnyOrder () Hamcrest

The containsInAnyOrdermatcher tidak seketat yang contains()pencocok: itu memungkinkan diuji elemen berada di urutan apapun dalam koleksi yang mengandung untuk lulus.

 /** * Test of addString and getStrings methods of class Main using Hamcrest * matcher containsInAnyOrder. */ @Test public void testAddStringAndGetStringsWithContainsInAnyOrder() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultCSharp = subject.addString("C#"); final boolean resultGroovy = subject.addString("Groovy"); final boolean resultScala = subject.addString("Scala"); final boolean resultClojure = subject.addString("Clojure"); final Set strings = subject.getStrings(); assertThat(strings, containsInAnyOrder("Java", "C#", "Groovy", "Scala", "Clojure")); } /** * Use containsInAnyOrder and show that order does not matter as long as * all entries provided are in the collection in some order. */ @Test public void testAddStringAndGetStringsWithContainsInAnyOrderAgain() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, containsInAnyOrder("Java", "Groovy")); assertThat(strings, containsInAnyOrder("Groovy", "Java")); } 

Dua pengujian unit yang ditampilkan tepat di atas kedua lulus meskipun String yang diuji diberikan kepada containsInAnyOrder()matcher dalam urutan yang berbeda dari yang mungkin ada di kedua koleksi. Namun, containsInAnyOrder()matcher yang kurang ketat masih mengharuskan semua elemen dari kumpulan yang memuatnya ditentukan agar lolos. Tes unit berikut tidak lulus karena kondisi ini tidak terpenuhi.

 /** * This will fail because containsInAnyOrder requires all items to be matched * even if in different order. With only one element being tried and two * elements in the collection, it will still fail. In other words, order * does not matter with containsInAnyOrder, but all elements in the collection * still need to be passed to the containsInAnyOrder matcher, just not in the * exact same order. */ @Test public void testAddStringAndGetStringsWithContainsInAnyOrderDiffNumberElements() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, containsInAnyOrder("Java")); } 

Hamcrest hasItem () dan hasItems () Matchers Bekerja Sebagai Suara

Seperti yang ditunjukkan dalam dua metode pengujian unit berikutnya (keduanya lolos), Hamcrest hasItem()(untuk item tunggal) dan hasItems(untuk beberapa item) berhasil menguji apakah suatu koleksi memiliki satu atau lebih dari satu item yang ditentukan masing-masing tanpa memperhatikan urutan atau nomor dari item tertentu. Ini benar-benar berfungsi lebih seperti kebanyakan pengembang Java yang biasa "berisi" saat bekerja dengan String dan koleksi.

 /** * Demonstrate hasItem() will also work for determining a collection contains * a particular item. */ @Test public void testAddStringAndGetStringsWithHasItem() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, hasItem("Groovy")); assertThat(strings, hasItem("Java")); } /** * Demonstrate that hasItems works for determining that a collection has one * or more items and that the number of items and the order of the items * is not significant in determining pass/failure. */ @Test public void testAddStringAndGetStringsWithHasItems() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat(strings, hasItems("Groovy", "Java")); assertThat(strings, hasItems("Java", "Groovy")); assertThat(strings, hasItems("Groovy")); assertThat(strings, hasItems("Java")); } 

Hamcrest isIn () Matcher Menguji Penahanan dari Arah Lain

Pencocokan yang baru saja dibahas hasItem()dan hasItems()pencocokan kurang ketat daripada contains()dan bahkan kurang ketat daripada containsInAnyOrder()dan sering kali menjadi keinginan seseorang ketika seseorang hanya ingin memastikan bahwa satu atau beberapa item ada di suatu tempat dalam koleksi tanpa mempedulikan urutan item dalam koleksi itu atau kemungkinan lainnya. item dalam koleksi itu. Satu cara lain untuk menggunakan Hamcrest untuk menentukan hubungan yang sama, tetapi dari perspektif yang berlawanan, adalah dengan menggunakan isInmatcher. The isInmatcher menentukan apakah item di suatu tempat dengan koleksi yang disediakan untuk pencocok tanpa memperhatikan agar item dalam koleksi atau apakah ada item lain dalam koleksi yang mengandung.

 /** * Use isIn matcher to test individual element is in provided collection. */ @Test public void testAddStringAndGetStringsWithIsIn() { final Main subject = new Main(); final boolean resultJava = subject.addString("Java"); final boolean resultGroovy = subject.addString("Groovy"); final Set strings = subject.getStrings(); assertThat("Groovy", isIn(strings)); assertThat("Java", isIn(strings)); }