如何在AssertJ递归比较中仅对集合元素启用严格类型检查?
问题描述
我希望使用AssertJ比较两个集合并启用严格类型检查,但仅关注集合元素的严格类型,而非集合本身的类型。例如,在测试代码中,我期望断言assertThat(listOfA).usingRecursiveComparison().withStrictTypeChecking().isEqualTo(arrayListOfA)结果为true,但当前结果为false——原因是listOfA为SingletonList类型,而arrayListOfA为ArrayList类型。同时要确保assertThat(listOfA).usingRecursiveComparison().withStrictTypeChecking().isNotEqualTo(arrayListOfB)能正确生效。
测试代码如下:
@Test fun `test`() { val listOfA = listOf(TestClassA("Name")) val arrayListOfA = arrayListOf(TestClassA("Name")) val arrayListOfB = arrayListOf(TestClassB("Name")) assertThat(listOfA).usingRecursiveComparison().isEqualTo(arrayListOfA) assertThat(listOfA).usingRecursiveComparison().isEqualTo(arrayListOfB) assertThat(listOfA).usingRecursiveComparison().withStrictTypeChecking().isEqualTo(arrayListOfA) assertThat(listOfA).usingRecursiveComparison().withStrictTypeChecking().isNotEqualTo(arrayListOfB) } class TestClassA(val name: String) class TestClassB(val name: String)
解决方案
可以通过自定义TypeComparator实现需求:让严格类型检查只作用于集合元素,忽略集合容器本身的类型差异。具体实现步骤如下:
- 自定义
TypeComparator,针对集合类型(如Iterable),跳过容器类型检查,转而递归比较元素;对非集合类型保留原有严格类型检查逻辑。 - 将自定义比较器注册到递归比较配置中。
修改后的测试代码如下:
@Test fun `test`() { val listOfA = listOf(TestClassA("Name")) val arrayListOfA = arrayListOf(TestClassA("Name")) val arrayListOfB = arrayListOf(TestClassB("Name")) // 自定义类型比较器:忽略集合容器类型,仅严格校验元素类型 val collectionTypeComparator = object : TypeComparator { override fun canCompare(o1: Any?, o2: Any?): Boolean { return o1 is Iterable<*> && o2 is Iterable<*> } override fun compare(o1: Any, o2: Any, comparisonContext: ComparisonContext?) { val iterable1 = o1 as Iterable<*> val iterable2 = o2 as Iterable<*> val list1 = iterable1.toList() val list2 = iterable2.toList() // 先校验元素数量是否一致 if (list1.size != list2.size) { throw AssertionError("集合元素数量不匹配:${list1.size} vs ${list2.size}") } // 逐个递归比较元素,启用严格类型检查 list1.zip(list2).forEachIndexed { index, (elem1, elem2) -> // 先检查元素类型是否一致 if (elem1?.javaClass != elem2?.javaClass) { throw AssertionError("索引$index 的元素类型不匹配:${elem1?.javaClass} vs ${elem2?.javaClass}") } // 用递归比较校验元素内容 RecursiveComparisonAssert(elem1, comparisonContext?.recursiveComparisonConfiguration) .usingRecursiveComparison() .withStrictTypeChecking() .isEqualTo(elem2) } } } // 注册自定义比较器后执行断言 assertThat(listOfA) .usingRecursiveComparison() .withStrictTypeChecking() .withComparator(collectionTypeComparator, Iterable::class.java) .isEqualTo(arrayListOfA) // 现在断言会通过 assertThat(listOfA) .usingRecursiveComparison() .withStrictTypeChecking() .withComparator(collectionTypeComparator, Iterable::class.java) .isNotEqualTo(arrayListOfB) // 此断言依然会正确生效 } class TestClassA(val name: String) class TestClassB(val name: String)
这种方式精准控制了类型检查的范围,既满足了忽略集合容器类型的需求,又保证了元素的严格类型校验。
内容的提问来源于stack exchange,提问作者mkapiczy
相关产品推荐
相关产品推荐

