走進Java接口測試之流式斷言庫AssertJ
前言
AssertJ簡介
AssertJ使用
導包
入門使用
對象斷言
布爾斷言
Iterable/Array斷言
字符斷言
類斷言
文件斷言
Double/Float/Integer斷言
Map斷言
Throwable 斷言
描述斷言
前言
AssertJ簡介
AssertJ使用
導包
入門使用
對象斷言
布爾斷言
Iterable/Array斷言
字符斷言
類斷言
文件斷言
Double/Float/Integer斷言
Map斷言
Throwable 斷言
描述斷言
小結
前言
在設計自動化接口 Cases 時,遵守的核心原則是3A(Arrange-> Actor ->Assert)原則;
斷言工具是否強大直接影響到用例的執行效率,本文將介紹目前主流的一種流式斷言神器:AssertJ。
AssertJ簡介
什么是流式,常見的斷言器一條斷言語句只能對實際值斷言一個校驗點,而流式斷言器,支持一條斷言語句對實際值同時斷言多個校驗點,簡單理解,即 AssertJ 斷言是可以串接的。
AssertJ 是一個 Java 庫,為 JDK 標準類型提供斷言,可以與 JUnit,TestNG 或任何其他測試框架一起使用。
不同的 AssertJ 主要版本依賴于不同的 Java 版本:
AssertJ 3.x 需要 Java 8或更高版本
AssertJ 2.x 需要 Java 7或更高版本
AssertJ 1.x 需要 Java 6或更高版本
請注意,AssertJ 3.x包含所有AssertJ 2.x功能,并添加了Java 8特定功能(如 lambdas 的異常斷言)
AssertJ 支持如下模塊:
Core:AssertJ core is a Java library that provides a fluent interface for writing assertions.
Assertions generator:Use the Assertion Generator to create assertions specific to your own classes.
Guava:AssertJ assertions for Guava provides assertions for Guava types like Multimap, Table, Optional, Range or ByteSource.
Joda-Time:AssertJ assertions for Joda-Time provides assertions for Joda-Time types like DateTime and LocalDateTime.
DB:AssertJ-DB provides assertions to test data in a database.
Neo4j:Provides assertions for Neo4j 3 or higher.
Swing:AssertJ Swing is a Java library that provides a fluent interface for functional Swing UI testing.
官方網站上提供了所有模塊的詳細列表。
地址:https://joel-costigliola.github.io/assertj/index.html
讓我們從幾個例子開始,直接來自 AssertJ 的官方文檔:
assertThat(frodo) .isNotEqualTo(sauron) .isIn(fellowshipOfTheRing); assertThat(frodo.getName()) .startsWith("Fro") .endsWith("do") .isEqualToIgnoringCase("frodo"); assertThat(fellowshipOfTheRing) .hasSize(9) .contains(frodo, sam) .doesNotContain(sauron);
以上的例子只是冰山一角,下面我們將介紹如何使用這個庫編寫斷言
AssertJ使用
導包
SpringBoot 內置了 AssertJ,只需要導入 spring-boot-starter-test 依賴包
入門使用
為了編寫一個斷言,你總是需要先將對象傳遞給 Assertions.assertThat() 方法,然后再按照實際的斷言進行操作。
重要的是要記住,與其他一些庫不同,下面的代碼實際上并沒有斷言任何東西,并且永遠不會失敗測試:
assertThat(anyRefenceOrValue);
如果你使用IDE的代碼完成功能,由于其描述性非常強的方法,編寫AssertJ 斷言變得異常簡單。下圖就是它在Intellij IDEA 中的樣子:
如圖所見,有許多可供選擇的上下文方法,并且這些方法僅適用于String類型。
對象斷言
可以以各種方式比較對象,以確定兩個對象的相等性或檢查對象的字段。
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Dog { private String name; private Float weight; }
讓我們看兩種方法,我們可以比較兩個對象的相等性。鑒于以下兩個Dog對象 fido和 fidosClone
@Test(description = "對象斷言1") public void whenComparingReferences_thenNotEqual() { // 實例化兩個對象 Dog fidos= new Dog("fidos",5.14f); Dog fidosClone = new Dog("fidosClone",5.14f); // 斷言兩個對象引用 assertThat(fidos).isNotEqualTo(fidosClone); }
isEqualTo() 是比較對象引用,所以會執行失敗。如果我們想要比較它們的內容,我們可以使用 isEqualToComparingFieldByFieldRecursively()
@Test(description = "對象斷言2") public void whenComparingFields_thenEqual() { // 實例化兩個對象 Dog fido = new Dog("Fido", 5.15f); Dog fidosClone = new Dog("Fido", 5.15f); // 斷言兩個對象內容 assertThat(fido).isEqualToComparingFieldByFieldRecursively(fidosClone); }
當通過字段比較執行遞歸字段時,Fido和fidosClone是相等的,因為一個對象的每個字段與另一個對象中的字段進行比較。
還有許多其他斷言方法提供了比較和收縮對象以及檢查和斷言其字段的不同方法。具體請參閱官方的 AbstractObjectAssert API。
布爾斷言
真值測試有一些簡單的方法:
isTrue()
isFalse()
舉個例子:
@Test(description = "布爾斷言") public void whenisEmpty_isTrue() { // 實例化對象 Dog fido = new Dog("Fido", 5.15f); // 斷言字段是否為空 assertThat(fido.getName().isEmpty()).isTrue(); }
Iterable/Array斷言
對于 Iterable 或 Array,有多種方法可以斷言它們的內容是否存在。最常見的斷言之一是檢查 Iterable 或 Array 是否包含給定元素:
或者如果 List 不為空:
assertThat(list).isNotEmpty();
或者如果 List 以給定字符開頭。例如“1”:
assertThat(list).startsWith("1");
如果要為同一對象創建多個斷言,可以輕松地將它們連接在一起。
下面是一個斷言示例,它檢查提供的列表是否為空,包含“1”元素,不包含任何空值并包含元素序列“2”,“3”:
assertThat(list) .isNotEmpty() .contains("1") .doesNotContainNull() .containsSequence("2", "3");
當然,對于那些類型存在更多可能的斷言 。具體請參閱官方的AbstractIterableAssert API
完整示例:
@Test(description = "Iterable/Array斷言1") public void whenCheckingForElement_thenContains(){ List
字符斷言
字符類型的斷言主要涉及比較,甚至檢查給定字符是否來自 Unicode 表。
下面是一個斷言示例,它檢查提供的字符是否不是 ‘a’,在 Unicode 表中,是否大于 ‘b’ 并且是小寫的:
assertThat(someCharacter) .isNotEqualTo('a') .inUnicode() .isGreaterThanOrEqualTo('b') .isLowerCase();
有關所有字符類型斷言的詳細列表,請參閱 AbstractCharacterAssertAPI
完整示例:
@Test(description = "字符斷言") public void whenCheckingCharacter_thenIsUnicode() { char someCharacter = 'c'; // 斷言字符是否不是 'a',在 Unicode 表中,是否大于 'b' 并且是小寫的 assertThat(someCharacter).isNotEqualTo('a').inUnicode().isGreaterThanOrEqualTo('b').isLowerCase(); }
類斷言
Class 類型的斷言主要是檢查其字段,類類型,注釋的存在和類的最終性。
如果你想斷言Runnable類是一個接口,你需要簡單地寫:
assertThat(Runnable.class).isInterface();
或者如果你想檢查一個類是否可以從另一個類中分配:
assertThat(Exception.class).isAssignableFrom(NoSuchElementException.class);
可以在 AbstractClassAssert API 中查看所有可能的類斷言。
完整示例:
@Test(description = "類斷言1") public void whenCheckingRunnable_thenIsInterface() { // 斷言Runnable類是一個接口 assertThat(Runnable.class).isInterface(); } @Test(description = "類斷言2") public void whenAssigningNSEExToException_thenIsAssignable(){ // 斷言一個類是否可以從另一個類中分配 assertThat(Exception.class).isAssignableFrom(NoSuchElementException.class); }
文件斷言
文件斷言都是關于檢查給定的文件實例是否存在,是目錄還是文件,具有某些內容,是否可讀或具有擴展名。
在這里斷言的示例,該斷言檢查給定文件是否存在,是文件而不是目錄,可讀寫的:
assertThat(someFile) .exists() .isFile() .canRead() .canWrite();
可以在 AbstractFileAssert API 中查看所有可能的類斷言。
完整示例:
@Test(description = "文件斷言") public void whenCheckingFile_then() throws IOException { final File someFile = File.createTempFile("aaa", "bbb"); someFile.deleteOnExit(); // 斷言文件是否存在,是文件而不是目錄,可讀寫的 assertThat(someFile).exists().isFile().canRead().canWrite(); }
Double/Float/Integer斷言
數字斷言都是關于比較給定偏移量內或沒有給定偏移量的數值。
例如,如果要根據給定的精度檢查兩個值是否相等,我們可以執行以下操作:
assertThat(5.1).isEqualTo(5, withPrecision(1d));
請注意,我們使用已導入的 withPrecision(雙偏移)輔助方法來生成偏移對象。
有關更多斷言,請訪問 AbstractDoubleAssert API。
InputStream斷言
只有一個可用的 InputStream 特定斷言:
hasSameContentAs(預期的 InputStream)
使用方法:
assertThat(given).hasSameContentAs(expected);
完整示例:
@Test(description = "InputStream斷言") public void whenCheckingIS_then() { InputStream given = new ByteArrayInputStream("foo".getBytes()); InputStream expected = new ByteArrayInputStream("foo".getBytes()); // 斷言是否預期的 InputStream assertThat(given).hasSameContentAs(expected); }
Map斷言
Map 斷言允許你分別檢查 Map 是否包含某些條目,條目集或鍵/值。
你可以看到斷言的示例,該斷言檢查給定的Map是否為空,包含key “2”,不包含數字鍵“10”并包含條目:key:2,value:“a”:
assertThat(map) .isNotEmpty() .containsKey(2) .doesNotContainKeys(10) .contains(entry(2, "a"));
有關更多斷言,請參閱 AbstractMapAssert API。
完整示例:
@Test(description = "Map斷言") public void whenGivenMap_then() { Map
Throwable 斷言
Throwable 的斷言允許例如:檢查異常的信息,蹤跡,原因檢查或者異常被拋出已驗證。
讓我們看一下斷言示例,該斷言檢查是否拋出了給定的異常并且消息以“c”結尾:
assertThat(ex).hasNoCause().hasMessageEndingWith("c");
有關更多斷言,請參閱 AbstractThrowableAssert API。
完整示例:
@Test(description = "Throwable斷言") public void whenGivenException_then() { Exception ex = new Exception("abc"); // 斷言是否拋出了給定的異常并且消息以“c”結尾 assertThat(ex).hasNoCause().hasMessageEndingWith("c"); }
描述斷言
為了獲得更高的詳細級別,你可以為斷言創建動態生成的自定義描述。
這樣做的關鍵是 as(String description,Object … args)方法。
如果你定義這樣的斷言:
assertThat(fidos.getWeight()) .as("%s's age should be equal to 5.15f") .isEqualTo(5.15f);
這是運行測試時的結果:
org.junit.ComparisonFailure: [%s's age should be equal to 5.15f] Expected :5.1[5]f Actual :5.1[4]f
完整示例:
@Test(description = "描述斷言") public void whenRunningAssertion_thenDescribed() throws Exception { Dog fidos= new Dog("fidos",5.14f); assertThat(fidos.getWeight()).as("%s's age should be equal to 5.15f").isEqualTo(5.15f); }
小結
在本文中,我們簡要探討了AssertJ 為核心Java類型提供最流行的流式斷言的使用方法。
本文源碼:
https://github.com/zuozewei/blog-example/tree/master/Java-api-test/07-assert/springboot-assertj-demo
Java 自動化測試
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。