You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为包含Address对象的列表创建AssertJ自定义断言?

自定义断言实现方案(基于AssertJ)

嘿,我来给你梳理下怎么把这段重复的断言逻辑封装成自定义断言,用AssertJ的话会非常顺手,步骤很清晰:

1. 先给Address对象写专属断言类

把城市、国家的校验逻辑封装到Address的断言类里,这样后续任何地方校验Address都能复用:

import org.assertj.core.api.AbstractAssert;

public class AddressAssert extends AbstractAssert<AddressAssert, Address> {

    // 私有构造,仅内部调用
    private AddressAssert(Address actual) {
        super(actual, AddressAssert.class);
    }

    // 静态工厂方法,方便外部链式调用
    public static AddressAssert assertThat(Address actual) {
        return new AddressAssert(actual);
    }

    // 封装城市校验,支持自定义失败提示
    public AddressAssert hasCity(String expectedCity, String failMessage) {
        isNotNull(); // 先确保Address不为null
        org.assertj.core.api.Assertions.assertThat(actual.getCity())
                .withFailMessage(failMessage)
                .isEqualTo(expectedCity);
        return this; // 返回自身支持链式调用
    }

    // 封装国家名称校验
    public AddressAssert hasCountryName(String expectedCountry) {
        isNotNull();
        org.assertj.core.api.Assertions.assertThat(actual.getCountryName())
                .isEqualTo(expectedCountry);
        return this;
    }
}

2. 给包含Address的父对象(比如你的P对象,假设叫Person)写断言类

如果你的列表元素是Person类(包含Address属性),再写一个Person的断言类,把Address的断言整合进来:

import org.assertj.core.api.AbstractAssert;

public class PersonAssert extends AbstractAssert<PersonAssert, Person> {

    private PersonAssert(Person actual) {
        super(actual, PersonAssert.class);
    }

    public static PersonAssert assertThat(Person actual) {
        return new PersonAssert(actual);
    }

    // 链式调用Address的断言,语义化更强
    public AddressAssert hasAddress() {
        isNotNull(); // 确保Person对象不为null
        return AddressAssert.assertThat(actual.getAddress());
    }
}

3. 在测试中使用自定义断言

现在原来的anySatisfy代码可以改写成更简洁、可读性更高的链式调用:

Assertions.assertThat(results.result)
          .anySatisfy(p -> 
              PersonAssert.assertThat(p)
                          .hasAddress()
                          .hasCity("Caseros1", "expected city: Caseros1")
                          .hasCountryName("Argentina")
          );

额外优化:封装列表级别的断言(可选)

如果这个校验逻辑经常用到,还可以进一步封装成针对Person列表的断言,让测试代码更简洁:

import org.assertj.core.api.AbstractListAssert;
import java.util.List;

public class PersonListAssert extends AbstractListAssert<PersonListAssert, List<Person>, Person, PersonAssert> {

    private PersonListAssert(List<Person> actual) {
        super(actual, PersonListAssert.class, PersonAssert::assertThat);
    }

    public static PersonListAssert assertThat(List<Person> actual) {
        return new PersonListAssert(actual);
    }

    // 直接封装"存在一个元素符合指定地址条件"的逻辑
    public PersonListAssert hasElementWithAddress(String expectedCity, String cityFailMessage, String expectedCountry) {
        anySatisfy(p -> 
            PersonAssert.assertThat(p)
                        .hasAddress()
                        .hasCity(expectedCity, cityFailMessage)
                        .hasCountryName(expectedCountry)
        );
        return this;
    }
}

这样测试代码就可以简化成一行:

PersonListAssert.assertThat(results.result)
                .hasElementWithAddress("Caseros1", "expected city: Caseros1", "Argentina");

这么做的好处很明显:

  • 复用性强:相同的校验逻辑不用重复写,哪里需要哪里调用
  • 可读性高:断言方法名都是语义化的,一眼就能明白要校验什么
  • 扩展性好:后续要加更多Address或Person的校验规则,直接在对应的断言类里加方法就行

内容的提问来源于stack exchange,提问作者Rejish R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:44:01