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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:25:07