在Assertj 3.16.1中,"hasOnlyElementsOfType "方法是否被废弃?

问题描述 投票:1回答: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 以代替给出问题的那个。有没有其他方法可以替代这些方法,达到同样的目的?

任何帮助将被感激!!!

java java-8 junit5 spring-test assertj
1个回答
4
投票

看来你是从AssertJ 3.12或更早的版本升级的。

错误是 AbstractObjectAssert 类没有 hasOnlyElementsOfType 方法。此外,它还 从来没有 有这个方法,所以并不是这个方法被废弃和删除了。相反,这段代码一定是有效的,因为 hasOnlyElementsOfType 被其他类调用。

在AssertJ中,大多数事情似乎都要经过 AbstractObjectAssert. 审视 AbstractObjectAssert 在AssertJ 3.12中,我看到它有一个方法是 extracting(String...) -- 一个varargs方法,返回 AbstractListAssert. 这个类又有一个 hasOnlyElementsOfType 方法继承自 AbstractIterableAssert. 编码 extracting("fault") 最终成为一个varargs调用。这反过来又返回 AbstractListAssert 因此,随后呼吁 hasOnlyElementsOfType 工作。

然而,在AssertJ 3.13中。AbstractObjectAssert 有一个新的方法 extracting(String) -- 一个varargs调用。该方法返回 AbstractObjectAssert 正如我们所看到的那样,它不具有 hasOnlyElementsOfType 方法。当针对这个版本的AssertJ(或更高版本)进行编译时,代码中的 extracting("fault") 解析为单参数过载。这将返回 AbstractObjectAssert 其中 拥有 hasOnlyElementsOfType 方法,因此出现错误。

为了解决这个问题,你可以强制调用到 extracting 来调用varargs重载而不是one-arg重载。varargs 调用只是在该位置传递数组的一些语法,所以你可以把你的代码改成这样。

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

这最终会调用varargs重载,它将返回 AbstractListAssert,它具有 hasOnlyElementsOfType 方法,所以即使在最近的AssertJ版本中也能正常工作。

作为一个旁白,这是一个相当罕见的添加方法导致不兼容的例子。通常情况下,添加方法不会影响任何现有的代码。然而,在现有的API中添加一个新的重载(就像AssertJ在3.13中所做的那样)可能会影响现有源代码的重载解析。也就是说,现有的针对旧版本编译的源代码最终会调用一些方法。当同样的源代码被编译到新版本时,它可能最终会调用新API中的一个不同的方法。如果这个新方法有不同的行为,可能会导致微妙的bug。在这种情况下,新方法有不同的返回类型,所以期望旧返回类型的代码不再工作。这正是这里发生的事情。


3
投票

Stuart Marks在纯AssertJ方面发了一篇很好的分析,没什么好补充的了 extracting(String) 只提取一个值,这意味着你只能用链式对象断言而不是列表断言(这是有道理的,因为你提取了一个值)。

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

assertThat(thrown).isInstanceOf(MyCustomException.class)
                  .extracting("fault")
                  .isInstanceOf(CustomException.class)
                  .extracting("code")
                  .isEqualTo("AnotherCustomException");
© www.soinside.com 2019 - 2024. All rights reserved.