[英]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.