JUnit测试中如何用AssertJ校验嵌套数组内的指定数据?
解决AssertJ嵌套集合/数组的余额金额校验问题
嘿,我刚好熟悉AssertJ的嵌套断言用法,帮你搞定这个问题!先明确下我假设的实体类结构(如果和你的实际代码有出入,调整对应的getter即可):
// 假设的实体类定义 class AccountResource { private String resourceId; private String currency; private List<BalanceResource> balances; // 如果是数组,后面会说明调整方式 // 标准getter方法 public String getResourceId() { return resourceId; } public String getCurrency() { return currency; } public List<BalanceResource> getBalances() { return balances; } } class BalanceResource { private String balanceType; private BalanceAmount balanceAmount; public String getBalanceType() { return balanceType; } public BalanceAmount getBalanceAmount() { return balanceAmount; } } class BalanceAmount { private BigDecimal amount; // 也可能是Integer,根据实际类型调整 public BigDecimal getAmount() { return amount; } }
你之前的测试已经用filteredOn定位到了目标账户,现在要嵌套校验余额的核心是:先锁定目标账户,再深入其balances集合过滤指定类型的余额,最后校验金额。之前用嵌套Lambda报错,大概率是没正确利用AssertJ的链式断言方法,或是没处理好集合的层级关系。
方案一:分步断言(清晰直观)
先提取目标账户,再单独对余额做校验,适合逻辑复杂的场景:
@Test void testClbdBalanceAmount() { List<AccountResource> accounts = ...; // 你的测试数据源 // 第一步:过滤出匹配的账户,确保只有一个(如果可能多个,换用其他断言) AccountResource targetAccount = assertThat(accounts) .filteredOn(account -> "010001781LV".equals(account.getResourceId())) .singleElement() .withFailMessage("找不到resourceId为010001781LV的账户,或匹配多个") .get(); // 第二步:在目标账户的balances中过滤CLBD类型的余额,校验金额 assertThat(targetAccount.getBalances()) .filteredOn(balance -> "CLBD".equals(balance.getBalanceType())) .singleElement() .withFailMessage("找不到balanceType为CLBD的余额,或匹配多个") .extracting(balance -> balance.getBalanceAmount().getAmount()) .isEqualTo(BigDecimal.valueOf(10000)); }
方案二:链式嵌套断言(更简洁)
用AssertJ的链式调用直接完成嵌套校验,不需要单独提取账户:
@Test void testClbdBalanceAmount_Chained() { List<AccountResource> accounts = ...; assertThat(accounts) // 过滤目标账户 .filteredOn(account -> "010001781LV".equals(account.getResourceId())) .singleElement() // 提取该账户的balances集合 .extracting(AccountResource::getBalances) .asList() // 明确告诉AssertJ这是List类型 // 过滤出CLBD类型的余额 .filteredOn(balance -> "CLBD".equals(balance.getBalanceType())) .singleElement() // 逐层提取balanceAmount和amount .extracting(BalanceResource::getBalanceAmount) .extracting(BalanceAmount::getAmount) // 校验金额值 .isEqualTo(BigDecimal.valueOf(10000)); }
如果你的balances是数组而不是List?
如果AccountResource中的balances是BalanceResource[]数组,只需把extracting(AccountResource::getBalances)换成flatExtracting(AccountResource::getBalances)即可,其他逻辑不变:
assertThat(accounts) .filteredOn(account -> "010001781LV".equals(account.getResourceId())) .singleElement() .flatExtracting(AccountResource::getBalances) // 数组用flatExtracting展开 .filteredOn(balance -> "CLBD".equals(balance.getBalanceType())) .singleElement() .extracting(balance -> balance.getBalanceAmount().getAmount()) .isEqualTo(BigDecimal.valueOf(10000));
常见报错原因排查
- 没有处理集合单一性:如果匹配的账户/余额不止一个,
singleElement()会报错,可换成contains()或anyMatch()等断言 - Getter方法问题:AssertJ依赖标准JavaBean getter(比如
getBalances()而非balances())提取属性 - 类型不匹配:比如
amount是Integer但用了BigDecimal断言,要和实体类类型保持一致
内容的提问来源于stack exchange,提问作者Stéphane GRILLON
相关产品推荐
相关产品推荐

