檢查清單中是否包含具有 Hamcrest 中某些屬性的元素
1. 概述
在使用 Java 編寫單元測試時,尤其是使用 JUnit 框架時,我們經常需要驗證清單中的元素是否具有特定屬性。
Hamcrest 是一個廣泛使用的Matcher函式庫,它提供了直接且富有表現力的方法來執行這些檢查。
在本教程中,我們將探索如何使用 JUnit 和 Hamcrest 的Matcher檢查清單是否包含具有特定屬性的元素。
2. 設定 Hamcrest 和範例
在設定範例之前,讓我們快速將 Hamcrest 依賴項新增至pom.xml :
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
我們可以在 Maven Central 中查看該工件的最新版本。
現在,讓我們建立一個簡單的 POJO 類別:
public class Developer {
private String name;
private int age;
private String os;
private List<String> languages;
public Developer(String name, int age, String os, List<String> languages) {
this.name = name;
this.age = age;
this.os = os;
this.languages = languages;
}
// ... getters are omitted
}
如程式碼所示, Developer類別擁有一些描述開發人員的屬性,例如開發人員的name 、 age,作業系統 ( os ) 以及開發人員主要使用的程式語言 ( languages )。
接下來,讓我們建立Developer實例的清單:
private static final List<Developer> DEVELOPERS = List.of(
new Developer("Kai", 28, "Linux", List.of("Kotlin", "Python")),
new Developer("Liam", 26, "MacOS", List.of("Java", "C#")),
new Developer("Kevin", 24, "MacOS", List.of("Python", "Go")),
new Developer("Saajan", 22, "MacOS", List.of("Ruby", "Php", "Typescript")),
new Developer("Eric", 27, "Linux", List.of("Java", "C"))
);
我們將以DEVELOPERS清單為例,介紹如何使用 JUnit 和 Hamcrest 檢查元素是否包含特定屬性。
3. 使用hasItem()和hasProperty()
Hamcrest 提供了一套豐富、方便的Matcher 。我們可以將hasProperty() Matcher與hasItem() Matcher結合使用:
assertThat(DEVELOPERS, hasItem(hasProperty("os", equalTo("Linux"))));
此範例示範如何檢查至少一個元素的os 是「 Linux 」。
我們可以將不同的屬性名稱傳遞給hasProperty()來驗證另一個屬性,例如:
assertThat(DEVELOPERS, hasItem(hasProperty("name", is("Kai"))));
在上面的範例中,我們使用 is() ( **equalTo() ,** is()別名)來檢查清單中是否有name等於“Kai”的元素。
當然,除了equalTo()和is()之外,我們還可以在hasProperty()中使用其他Matcher以不同的方式驗證元素的屬性:
assertThat(DEVELOPERS, hasItem(hasProperty("age", lessThan(28))));
assertThat(DEVELOPERS, hasItem(hasProperty("languages", hasItem("Go"))));
斷言語句讀起來就像自然語言,例如:“ assertThat the DEVELOPERS list hasItem which hasProperty who name isage and value is lessThan 28″ 。
anyOf()和allOf()匹配器
hasProperty()可以方便檢查一個屬性。我們也可以透過使用 anyOf() 和[**allOf() .**](https://hamcrest.org/JavaHamcrest/javadoc/2.2/org/hamcrest/Matchers.html#allOf-org.hamcrest.Matcher...-) anyOf()多個hasProperty()呼叫來檢查清單中的元素是否滿足多個屬性。
如果anyOf()內的任何一個Matcher被匹配,則整個anyOf()就滿足。接下來我們透過一個例子來理解:
assertThat(DEVELOPERS, hasItem(
anyOf(
hasProperty("languages", hasItem("C")),
hasProperty("os", is("Windows"))) // <-- No dev has the OS "Windows"
));
如範例所示,儘管DEVELOPERS清單中沒有元素的os等於“Windows” ,但斷言會通過,因為我們有一個元素 ( “Eric” ) 的languages包含「 C 」。
因此, anyOf()對應於「OR」邏輯:如果有任何元素的languages包含「 C 」OR os就是「 Windows 」。
相反, allOf()執行“AND”邏輯。接下來,我們來看一個例子:
assertThat(DEVELOPERS, hasItem(
allOf(
hasProperty("languages", hasItem("C")),
hasProperty("os", is("Linux")),
hasProperty("age", greaterThan(25)))
));
在上面的測試中,我們檢查**DEVELOPERS中的至少一個元素是否同時滿足allOf().中的三個hasProperty() Matcher 。**
由於「 Eric 」的屬性通過了三個hasProperty() Matcher檢查,因此測試通過。
接下來,我們對測試進行一些更改:
assertThat(DEVELOPERS, not(hasItem( // <-- not() matcher
allOf(
hasProperty("languages", hasItem("C#")),
hasProperty("os", is("Linux")),
hasProperty("age", greaterThan(25)))
)));
這次,我們沒有匹配項,因為沒有元素可以通過所有三個hasProperty() Matcher 。
5.使用JUnit的assertTrue()和Stream.anyMatch()
Harmcrest 提供了方便的方法來驗證清單中的元素是否具有特定屬性。或者,我們可以使用標準 JUnit assertTrue()斷言和 Java Stream API 中的anyMatch()來執行相同的檢查。
如果流中的任何元素通過檢查函數, anyMatch()方法將傳回true 。接下來,我們來看一些例子:
assertTrue(DEVELOPERS.stream().anyMatch(dev -> dev.getOs().equals("Linux")));
assertTrue(DEVELOPERS.stream().anyMatch(dev -> dev.getAge() < 28));
assertTrue(DEVELOPERS.stream().anyMatch(dev -> dev.getLanguages().contains("Go")));
值得注意的是,當我們使用 lambda 來檢查元素的屬性時,我們可以直接呼叫 getter 方法來取得它們的值。這比 Hamcrest 的hasProperty() Matcher更容易,後者需要屬性名稱作為文字String 。
當然,如果需要,我們可以輕鬆擴展 lambda 表達式來進行複雜的檢查:
assertTrue(DEVELOPERS.stream().anyMatch(dev -> dev.getLanguages().contains("C") && dev.getOs().equals("Linux")));
上面的測試顯示了一個 lambda 表達式來檢查流中元素的多個屬性。
六,結論
在本文中,我們探索了使用 JUnit 和 Hamcrest 斷言清單是否包含具有某些屬性的元素的各種方法。
無論是使用簡單屬性還是組合多個條件,Hamcrest 都提供了一個強大的工具包來驗證集合中元素的屬性。此外,Hamcrest Matcher使我們的測試更具可讀性和表現力,增強了測試程式碼的清晰度和可維護性。
或者,我們可以使用 Stream API 中的 JUnit assertTrue()和anyMatch()執行此類檢查。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。