如何为包含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
相关产品推荐
相关产品推荐

