[英]Can you add a custom message to AssertJ assertThat?
我們有一個測試套件,主要使用帶有 Hamcrest 匹配器的 JUnit 斷言。 我們的一個團隊開始試驗AssertJ ,它的語法、靈活性和聲明性給人們留下了深刻的印象。 JUnit 提供了一項我在 AssertJ 中找不到的等效功能:添加自定義斷言失敗消息。
我們經常比較那些不是為了人類可讀性而制作的對象,它們具有隨機的 Id 或 UUID,並且不可能通過它們包含的數據來判斷它們應該是什么。 遺憾的是,對於我們的代碼庫來說,這是不可避免的情況,因為它實現的部分目的是在其他服務之間映射數據,而不必了解它是什么。
在 JUnit 中, assertThat
方法在Matcher<T>
參數之前提供了一個帶有String reason
參數的版本。 這使得添加一個簡短的調試字符串來闡明問題變得微不足道,比如比較對人類意味着什么。
另一方面,AssertJ 提供了無數不同的泛化static assertThat
方法,這些方法返回某種形式的接口 Assert或其許多實現類中的一個。 此接口不提供設置要包含在故障中的自定義消息的標准方法。
有什么方法可以從 AssertJ API 或其擴展之一獲得此功能,而不必為我們想要添加消息的每個斷言類型創建自定義斷言類?
以經典的方式,我在發布問題后找到了我正在尋找的東西。 希望這會讓下一個人更容易找到,而不必先知道它叫什么。 神奇的方法是具有欺騙性的短名稱as
,它是AbstractAssert
實現的另一個接口的一部分: Descriptable ,而不是基本的 Assert 接口。
public S as(String description, Object... args)
設置此對象的描述支持
String.format(String, Object...)
語法。
例子 :try { // set a bad age to Mr Frodo which is really 33 years old. frodo.setAge(50); // you can specify a test description with as() method or describedAs(), it supports String format args assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(33); } catch (AssertionError e) { assertThat(e).hasMessage("[check Frodo's age] expected:<[33]> but was:<[50]>"); }
如果斷言失敗,catch 塊hasMessage
中引用的字符串是單元測試輸出日志中出現的內容。
我通過注意到問題中鏈接的自定義斷言頁面中的failWithMessage
幫助器發現了這一點。 該方法的JavaDoc指出它是受保護的,因此調用者不能使用它來設置自定義消息。 然而,它確實提到了as
助手:
此外,此方法遵循使用
as(String, Object...)
設置的任何描述或用戶使用overridingErrorMessage(String, Object...)
定義的覆蓋錯誤消息。
......而overridingErrorMessage幫手,它完全取代了標准的AssertJ expected: ... but was:...
所提供的新的字符串消息。
在功能突出顯示頁面之前,AssertJ 主頁沒有提到任何一個助手,該頁面在軟斷言部分顯示了as
助手的示例,但沒有直接描述它的作用。
為 Patrick M 的答案添加另一個選項:
除了使用Descriptable.as
,您還可以使用AbstractAssert.withFailMessage()
:
try {
// set a bad age to Mr Frodo which is really 33 years old.
frodo.setAge(50);
// you can specify a test description via withFailMessage(), supports String format args
assertThat(frodo.getAge()).
withFailMessage("Frodo's age is wrong: %s years, difference %s years",
frodo.getAge(), frodo.getAge()-33).
isEqualTo(33);
} catch (AssertionError e) {
assertThat(e).hasMessage("Frodo's age is wrong: 50 years, difference 17 years");
}
使用Descriptable.as
的不同之處在於它讓您可以完全控制自定義消息- 沒有“預期”和“但是”。
當被測試的實際值對演示沒有用時,這很有用 - 此方法允許您顯示其他可能計算的值,或者根本不顯示。
請注意,就像Descriptable.as
一樣,您必須在任何實際斷言之前調用withFailMessage()
- 否則它將不起作用,因為斷言將首先觸發。 這在 Javadoc 中有說明。
僅供參考,新的AssertJ網站(目前仍在建設中,但已經有了有用的信息),請參閱https://assertj.github.io/doc/#assertj-core-assertion-description 。
使用 AssertJ 中內置的as()
方法。 例如:
assertThat(myTest).as("The test microservice is not active").isEqualTo("active");
到目前為止提到的兩個選項是as
和withFailMessage
,所以我不會再次討論語法或用法。 要了解它們之間的區別,以及它們的用途,請考慮我們正在測試導出的指標的用例:
// map of all metrics, keyed by metrics name
Map<String, Double> invocations = ...
List.of(
"grpc.client.requests.sent",
"grpc.client.responses.received",
"grpc.server.requests.received",
"grpc.server.responses.sent"
).forEach { counter ->
var meter = // create meter name using counter
assertThat(invocations)
.withFailMessage("Meter %s is not found", meter)
.containsKey(meter)
assertThat(invocations.get(meter))
.as(meter)
.isEqualTo(0.0)
}
我使用 Java 11 語法來減少一些樣板文件。
如果沒有withFailMessage
,如果地圖中不存在儀表,則默認輸出包含地圖中所有條目的轉儲,這會使測試日志withFailMessage
。 我們不關心其他儀表是否存在,只關心我們想要的儀表在那里。
使用withFailMessage
,輸出變為:
java.lang.AssertionError: Meter blah is not found
至於as
,它只將給定的消息附加到輸出中,但保留了失敗的比較,這非常有用。 我們得到:
org.opentest4j.AssertionFailedError: [blah]
Expecting:
<1.0>
to be equal to:
<0.0>
but was not.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.