AssertJ提取列表后调用first()返回List而非预期对象问题
解决AssertJ中
.first()返回List而非预期String的问题 你遇到的错误很典型:
java.lang.AssertionError: [List check first element] Expecting: <["Malaysia"]> to be an instance of: <java.lang.String> but was instance of: <java.util.ArrayList>
本来期望.first()返回String类型的元素,结果它返回了整个List<String>,这是因为extracting()的行为和你预期的不一样。
问题根源
当你对单个Region对象调用.extracting(Region::getCountries)时,AssertJ并不会直接把提取到的List<String>作为断言目标——它会把这个列表包装成一个只包含该列表的Iterable。也就是说:
.hasSize(1)验证的是这个包装后的Iterable的大小(确认我们成功提取到了一个属性值),而不是countries列表本身的元素数量。.first()取的是这个Iterable的第一个元素,也就是整个List<String>,而非列表里的"Malaysia"字符串。
解决方案
这里有几种简洁的修复方式:
方案1:用flatExtracting()展开集合属性
flatExtracting()会自动拆解集合类型的属性,直接把集合内的元素作为断言的目标Iterable。这样后续的断言就完全符合你的预期了:
assertThat(asia) .isInstanceOfSatisfying(Region.class, regionRequirement) .flatExtracting(Region::getCountries) .hasSize(1) .first() .isInstanceOfSatisfying(String.class, countryRequirement);
方案2:嵌套断言操作List元素
如果你想保留extracting(),可以在提取到List后,再对List本身进行嵌套断言,明确获取它的第一个元素:
assertThat(asia) .isInstanceOfSatisfying(Region.class, regionRequirement) .extracting(Region::getCountries) .first() // 获取到整个countries列表 .hasSize(1) .first() // 获取列表中的第一个String元素 .isInstanceOfSatisfying(String.class, countryRequirement);
方案3:用satisfies()直接断言属性
这种方式最直观,直接针对Region的countries属性做断言,完全绕开extracting()的包装问题:
assertThat(asia) .isInstanceOfSatisfying(Region.class, regionRequirement) .satisfies(region -> assertThat(region.getCountries()) .hasSize(1) .first() .isInstanceOfSatisfying(String.class, countryRequirement));
总结
推荐使用方案1或方案3,代码更简洁易读,也更符合AssertJ的设计意图。
内容的提问来源于stack exchange,提问作者Rashidi Zin
相关产品推荐
相关产品推荐

