AssertJ
AssertJ的三大核心价值:
流式API:链式调用结构使断言逻辑更贴近自然语言
assertThat(user.getName())
.isEqualTo("Alice")
.startsWith("A")
.contains("lic");
语义化方法:提供isEqualTo
、isInstanceOf
等自解释方法名
// 传统JUnit
assertEquals("expected", actual);
// AssertJ
assertThat(actual).isEqualTo("expected");
智能类型推断:自动处理null值和集合类型
assertThat(list).containsExactly("a", "b"); // 自动处理集合
assertThat(obj).isNull(); // 明确处理null值
环境搭建
Maven依赖
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
Gradle依赖
testImplementation 'org.assertj:assertj-core:3.24.2'
基础断言实战
对象属性验证
User user = new User("Alice", 30);
assertThat(user.getName())
.isEqualTo("Alice")
.isInstanceOf(String.class)
.startsWith("A")
.contains("lic");
assertThat(user.getAge())
.isEqualTo(30)
.isGreaterThan(18)
.isLessThan(65);
集合验证
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
assertThat(names)
.hasSize(3)
.contains("Alice", "Bob")
.doesNotContain("David")
.isSorted(); // 验证自然排序
异常验证
Throwable thrown = catchThrowable(() -> {
divide(10, 0);
});
assertThat(thrown)
.isInstanceOf(ArithmeticException.class)
.hasMessageContaining("by zero");
流式API
链式提取属性
assertThat(user)
.extracting(User::getName, User::getAge)
.containsExactly("Alice", 30);
集合分组验证
Map<String, Integer> ages = Map.of("Alice", 30, "Bob", 25);
assertThat(ages)
.hasSize(2)
.containsOnlyKeys("Alice", "Bob")
.extractingByValue()
.allMatch(age -> age > 18);
时间验证
LocalDateTime now = LocalDateTime.now();
assertThat(now)
.isBefore(now.plusHours(1))
.isAfter(now.minusDays(1))
.hasYear(2023)
.hasMonth(Month.APRIL);
自定义断言扩展
创建自定义断言
public class CustomAssertions {
public static StringAssert assertThat(String actual) {
return new StringAssert(actual);
}
}
public class StringAssert extends AbstractAssert<StringAssert, String> {
public StringAssert(String actual) {
super(actual, StringAssert.class);
}
public StringAssert isPalindrome() {
String reversed = actual.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
String original = new StringBuilder(reversed).reverse().toString();
if (!reversed.equals(original)) {
failWithMessage("Expected <%s> to be a palindrome", actual);
}
return this;
}
}
使用自定义断言
assertThat("A man, a plan, a canal: Panama")
.as("Palindrome check")
.isPalindrome();
与测试框架集成
JUnit 5集成
@Test
void testUserCreation() {
User user = new User("Alice", 30);
assertAll("User properties",
() -> assertThat(user.getName()).isEqualTo("Alice"),
() -> assertThat(user.getAge()).isEqualTo(30)
);
}
TestNG集成
@Test
public void testListContents() {
List<String> names = Arrays.asList("Alice", "Bob");
SoftAssertions softly = new SoftAssertions();
softly.assertThat(names).contains("Alice");
softly.assertThat(names).hasSize(2);
softly.assertAll();
}