Hamcrest包含匹配器
與Hamcrest 1.2相比 ,針對(duì)Matchers類的Hamcrest 1.3 Javadoc文檔為該類的幾種方法添加了更多文檔。 例如,四個(gè)重載的contains方法具有更具描述性的Javadoc文檔,如下面所示的兩個(gè)比較屏幕快照所示。
盡管僅通過嘗試就可以弄清楚“包含”匹配器的工作方式,但是Hamcrest 1.3中的Javadoc使得閱讀它們的工作方式更加容易。 大多數(shù)Java開發(fā)人員在考慮contains()方法時(shí),可能會(huì)想到類似String.contains(CharSequence)或Collection.contains(Object)的行為。 換句話說,大多數(shù)Java開發(fā)人員可能將“包含”描述為描述String / Collection是否包含提供的字符/對(duì)象以及其他可能的字符/對(duì)象。 但是,對(duì)于Hamcrest匹配器,“包含”具有更具體的含義。 隨著Hamcrest 1.3文檔更加清晰明了,“包含”匹配項(xiàng)對(duì)傳遞給這些方法的項(xiàng)目數(shù)量和項(xiàng)目順序更加敏感。
此處顯示的示例使用JUnit和Hamcrest。 這里要強(qiáng)調(diào)的是,Hamcrest的JAR文件必須在JUnit的JAR文件之前出現(xiàn)在單元測(cè)試的類路徑中,否則我必須使用為與獨(dú)立的Hamcrest JAR一起使用而構(gòu)建的“特殊” JUnit JAR文件。 使用這些方法之一可以避免NoSuchMethodError和其他錯(cuò)誤(例如org.hamcrest.Matcher.describeMismatch錯(cuò)誤),這是由類的版本不匹配導(dǎo)致的。 我已經(jīng)在JUnit的博客超越核心Hamcrest中撰寫了有關(guān)JUnit / Hamcrest細(xì)微差別的文章。
接下來的兩個(gè)屏幕快照指示了單元測(cè)試代碼段的結(jié)果(如NetBeans 7.3所示),我將在稍后的博客中展示這些單元測(cè)試代碼段,以演示包含匹配器的Hamcrest。 這些測(cè)試應(yīng)該有一些失敗(7個(gè)測(cè)試通過,4個(gè)測(cè)試失敗),以使Hamcrest匹配器在不閱讀Javadoc的情況下可能無法按預(yù)期工作的地方很明顯。 第一張圖片僅顯示5個(gè)測(cè)試通過,2個(gè)測(cè)試失敗和4個(gè)測(cè)試導(dǎo)致錯(cuò)誤。 這是因?yàn)樵贜etBeans項(xiàng)目的“測(cè)試庫(kù)”類路徑中,在Hamcrest之前列出了JUnit。 第二個(gè)圖像顯示了預(yù)期的結(jié)果,因?yàn)镠amcrest JAR發(fā)生在項(xiàng)目的“測(cè)試庫(kù)”類路徑中的JUnit JAR之前。
為了演示的目的,我有一個(gè)簡(jiǎn)單的人為設(shè)計(jì)的類要測(cè)試。 接下來顯示該Main類的源代碼。
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<String> strings = new HashSet<>();public Main() {}public boolean addString(final String newString){return this.strings.add(newString);}public Set<String> getStrings(){return Collections.unmodifiableSet(this.strings);} }顯示了要測(cè)試的類之后,現(xiàn)在該考慮使用Hamcrest匹配器構(gòu)建一些基于JUnit的測(cè)試了。 具體來說,測(cè)試是為了確保通過類的addString(String)方法添加的addString(String)位于其基礎(chǔ)Set并且可以通過getStrings()方法訪問。 接下來顯示的單元測(cè)試方法演示了如何適當(dāng)?shù)厥褂肏amcrest匹配器來確定類的基礎(chǔ)Set是否包含添加的字符串。
在Set Works中將Hamcrest contains()匹配器與單個(gè)字符串一起使用
/*** 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.*/@Testpublic void testAddStringAndGetStringsWithContainsForSingleStringSoWorks(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final Set<String> strings = subject.getStrings();assertThat(strings, contains('Java'));}上面顯示的單元測(cè)試通過了,因?yàn)镾et僅包含一個(gè)字符串,因此使用contains匹配項(xiàng)進(jìn)行測(cè)試的字符串的順序和數(shù)量匹配。
如果訂單匹配,則使用具有相同數(shù)量元素的Hamcrest容器有效
/*** 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.*/@Testpublic void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks1(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> 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.*/@Testpublic void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks2(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat(strings, contains('Groovy', 'Java'));}上面顯示的兩個(gè)示例單元測(cè)試以及運(yùn)行這些測(cè)試的結(jié)果輸出(如上一個(gè)屏幕快照所示)顯示,只要contains()匹配器的參數(shù)數(shù)量與要測(cè)試的集合中的Strings數(shù)量相同, , 如果所測(cè)試的元素與集合中的元素完全相同的順序,則匹配可能有效。 對(duì)于無序的Set ,不能依賴此順序,因此contains()不太可能是與多個(gè)元素的Set上的單元測(cè)試一起使用的良好匹配器。
使用具有不同數(shù)量元素的Hamcrest容器永遠(yuǎn)行不通
/*** Demonstrate that contains will NOT pass when there is a different number* of elements asked about contains than in the collection.*/@Testpublic void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements1(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> 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.*/@Testpublic void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements2(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat(strings, contains('Groovy'));}作為JUnit測(cè)試結(jié)果表明,這兩個(gè)單元測(cè)試從未通過,因?yàn)樵诒粶y(cè)試元件的數(shù)目Set為比在元件的數(shù)量較少的Set 。 換句話說,這證明了contains()匹配器不會(huì)簡(jiǎn)單地測(cè)試集合中的給定元素:它會(huì)測(cè)試所有指定元素的存在和指定順序。 在某些情況下,這可能太過局限了,所以現(xiàn)在我將繼續(xù)進(jìn)行Hamcrest提供的其他一些確定項(xiàng),以確定特定集合中是否包含元素。
使用Hamcrest的containsInAnyOrder()匹配器
containsInAnyOrder匹配器不如contains()匹配器嚴(yán)格:它允許被測(cè)試的元素以任何順序通過包含集合中的元素。
/*** Test of addString and getStrings methods of class Main using Hamcrest* matcher containsInAnyOrder.*/@Testpublic 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<String> 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.*/@Testpublic void testAddStringAndGetStringsWithContainsInAnyOrderAgain(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat(strings, containsInAnyOrder('Java', 'Groovy'));assertThat(strings, containsInAnyOrder('Groovy', 'Java'));}上方顯示的兩個(gè)單元測(cè)試都通過了,盡管被測(cè)試的字符串以與兩個(gè)集合中可能存在的順序不同的順序提供給containsInAnyOrder()匹配器。 但是,不太嚴(yán)格的containsInAnyOrder()匹配器仍要求將包含集合的所有元素指定為傳遞。 由于不滿足此條件,因此以下單元測(cè)試未通過。
/*** 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.*/@Testpublic void testAddStringAndGetStringsWithContainsInAnyOrderDiffNumberElements(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat(strings, containsInAnyOrder('Java'));}Hamcrest hasItem()和hasItems()匹配器像聲音一樣工作
如接下來的兩個(gè)單元測(cè)試方法(均通過)所示,Hamcrest hasItem() (用于單個(gè)項(xiàng)目)和hasItems (用于多個(gè)項(xiàng)目)成功地測(cè)試了一個(gè)集合分別具有一個(gè)或多個(gè)指定項(xiàng)目,而無需考慮用于指定項(xiàng)目的訂單或數(shù)量。 這實(shí)際上更像大多數(shù)Java開發(fā)人員在處理Strings和collections時(shí)“包含”工作。
/*** Demonstrate hasItem() will also work for determining a collection contains* a particular item.*/@Testpublic void testAddStringAndGetStringsWithHasItem(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> 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.*/@Testpublic void testAddStringAndGetStringsWithHasItems(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat(strings, hasItems('Groovy', 'Java'));assertThat(strings, hasItems('Java', 'Groovy'));assertThat(strings, hasItems('Groovy'));assertThat(strings, hasItems('Java'));}Hamcrest isIn()匹配器從其他方向測(cè)試遏制
剛剛討論過的hasItem()和hasItems()匹配器不如contains()嚴(yán)格,甚至不如containsInAnyOrder()嚴(yán)格,并且經(jīng)常是人們想要簡(jiǎn)單地確保一個(gè)或多個(gè)項(xiàng)目在集合中某處而又沒有的情況下想要的關(guān)注該集合中的項(xiàng)目順序或該集合中其他可能的項(xiàng)目。 使用Hamcrest確定相同關(guān)系的另一種方法是使用isIn匹配器,但從相反的角度來看。 isIn匹配器確定某個(gè)項(xiàng)目是否位于提供給匹配器的集合的某個(gè)位置,而無需考慮該項(xiàng)目在集合中的順序,或者不考慮該集合中是否還有其他項(xiàng)目。
/*** Use isIn matcher to test individual element is in provided collection.*/@Testpublic void testAddStringAndGetStringsWithIsIn(){final Main subject = new Main();final boolean resultJava = subject.addString('Java');final boolean resultGroovy = subject.addString('Groovy');final Set<String> strings = subject.getStrings();assertThat('Groovy', isIn(strings));assertThat('Java', isIn(strings));}結(jié)論
Hamcrest提供了一組豐富的匹配器,可用于確定指定的元素是否駐留在指定的集合中。 在決定應(yīng)用這些和確定使用哪個(gè)時(shí),請(qǐng)記住以下重要點(diǎn):
- 確保Hamcrest JAR在JUnit JAR之前位于測(cè)試類路徑上。
- 使用contains當(dāng)你想確保集合包含了所有規(guī)定的項(xiàng)目,沒有其他物品,你想收集包含指定順序的項(xiàng)目。
- 通常應(yīng)避免對(duì)Set s使用contains()匹配器,因?yàn)樗鼈儽举|(zhì)上是無序的。
- 當(dāng)您仍要嚴(yán)格測(cè)試是否在測(cè)試中指定的集合中存在完全相同的項(xiàng)目時(shí),請(qǐng)使用containsInAnyOrder匹配器,但不必關(guān)心順序(適用于Set )。
- 使用hasItem()和hasItems()匹配器詢問集合是否包含(可能在其他未列出的項(xiàng)目中,并且沒有特定的順序)指定的項(xiàng)目。
- 使用isIn()匹配器詢問特定項(xiàng)是否在指定的集合中,而與其他項(xiàng)是否在該集合中或該項(xiàng)在包含的集合中的順序無關(guān)。
參考:來自我們的JCG合作伙伴 Dustin Marx的Hamcrest包含匹配器 ,位于Inspired by Actual Events博客上。
翻譯自: https://www.javacodegeeks.com/2013/01/hamcrest-containing-matchers.html
總結(jié)
以上是生活随笔為你收集整理的Hamcrest包含匹配器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vs2010 rdlc 报表及报表控件
- 下一篇: 第三步 费率查询