"hasOnlyElementsOfType" 方法是否在 Assertj 3.16.1 中弃用

Is the method "hasOnlyElementsOfType" deprecated in Assertj 3.16.1

我的这段代码在更新到 Assertj 3.16.1 后不再有效

Throwable thrown = catchThrowable(() -> myObject.methodThrowsException());
assertThat(thrown).isInstanceOf(MyCustomException.class).extracting("fault").hasOnlyElementsOfType(CustomException.class).extracting("code").containsExactly("AnotherCustomException");

我收到此错误消息:

java:cannot find symbol
symbol: method hasOnlyElementsOfType(java.lang.Class<CustomException.class>)
location: class org.assertj.core.api.AbstractObjectAssert<capture#1 of?, capture#2 of ?>

它要么被弃用,要么现在以不同的方式实现。我已经浏览了文档并搜索了将近两天,以查看是否有任何关于如何使用它的信息,而不是以前如何使用它来实现轻松过渡,但尚未找到任何信息。当我使用此 containsOnlyOnceElementsOf 代替给出问题的错误时,我实际上遇到了类似的错误。除了这些方法之外,还有其他方法可以实现相同的目的吗?

任何帮助将不胜感激!!!

您似乎是从 AssertJ 3.12 或更早版本升级的。

错误是 AbstractObjectAssert class 没有 hasOnlyElementsOfType 方法。此外,它 从未 拥有该方法,因此该方法并不是被弃用和删除的情况。相反,这段代码一定是有效的,因为 hasOnlyElementsOfType 被其他 class.

调用了

AssertJ 中的大部分内容似乎都经过 AbstractObjectAssert。查看 AssertJ 3.12 中的 AbstractObjectAssert,我看到它有一个方法 extracting(String...) —— 一个可变参数方法 —— 即 returns AbstractListAssert。这个 class 又继承自 AbstractIterableAsserthasOnlyElementsOfType 方法。代码 extracting("fault") 最终成为可变参数调用。这反过来 returns AbstractListAssert ,因此随后对 hasOnlyElementsOfType 的调用有效。

但是,在 AssertJ 3.13 中,AbstractObjectAssert 有一个新方法 extracting(String) -- NOT 可变参数调用。正如我们所见,returns AbstractObjectAssert 方法没有 hasOnlyElementsOfType 方法。针对此版本的 AssertJ(或更高版本)编译时,代码 extracting("fault") 解析为一个参数重载。这个 returns AbstractObjectAssert NOThasOnlyElementsOfType 方法,因此错误。

要解决此问题,您可以强制调用 extracting 以调用可变参数重载而不是单参数重载。可变参数调用只是在该位置传递数组的一些语法,因此您可以将代码更改为如下内容:

....extracting(new String[] { "fault" })....

这最终调用了可变参数重载,它 returns AbstractListAssert,它有你接下来要调用的 hasOnlyElementsOfType 方法,所以即使在最近的 AssertJ 中也应该可以工作版本。

顺便说一句,这是一个相当罕见的示例,其中添加方法会导致不兼容。通常添加方法不会影响任何现有代码。但是,向现有 API 添加新的重载(如 AssertJ 在 3.13 中所做的那样)可能会影响现有源代码的重载解析。也就是说,针对旧版本编译的现有源代码最终将调用某些方法。当针对新版本编译相同的源代码时,它最终可能会在新 API 中调用不同的方法。如果该新方法具有不同的行为,则可能会导致细微的错误。在这种情况下,新方法具有不同的 return 类型,因此需要旧 return 类型的代码不再有效。这正是这里发生的事情。

Stuart Marks 发表了一篇很棒的分析,没有什么可补充的,在事物的纯 AssertJ 方面 extracting(String) 只提取一个值,这意味着你只能链接对象断言而不是列表断言(有意义因为您提取了单个值)。

我相信你可以做以下断言:

assertThat(thrown).isInstanceOf(MyCustomException.class)
                  .extracting("fault")
                  .isInstanceOf(CustomException.class)
                  .extracting("code")
                  .isEqualTo("AnotherCustomException");