为何Hamcrest的arrayWithSize在Kotlin中无法正常工作?
Kotlin中使用Hamcrest断言IntArray长度出现类型不匹配问题
我尝试用Hamcrest测试整数数组的长度,编写了如下Kotlin代码:
import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.collection.IsArrayWithSize.arrayWithSize import org.hamcrest.core.IsEqual.equalTo import org.hamcrest.core.Is.`is` as Is … val parts = intArrayOf(1, 2, 3) assertThat(parts, arrayWithSize(3)) assertThat(parts, Is(arrayWithSize(3))) assertThat(parts, Is(arrayWithSize(equalTo(3))))
据我理解这三种断言写法在Java中都能正常运行,但在Kotlin里却报出以下错误:
[ERROR] …/Decomposed_Test.kt:[287,14] Type mismatch: inferred type is IntArray but String! was expected [ERROR] …/Decomposed_Test.kt:[287,21] Type mismatch: inferred type is Matcher<Array<(???..???)>!>! but Boolean was expected [ERROR] …/Decomposed_Test.kt:[288,14] Type mismatch: inferred type is IntArray but String! was expected [ERROR] …/Decomposed_Test.kt:[288,21] Type mismatch: inferred type is Matcher<(???..???)>! but Boolean was expected [ERROR] …/Decomposed_Test.kt:[289,14] Type mismatch: inferred type is IntArray but String! was expected [ERROR] …/Decomposed_Test.kt:[289,21] Type mismatch: inferred type is Matcher<(???..???)>! but Boolean was expected
错误提示明显不符合实际,我尝试为断言添加描述信息:
import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.collection.IsArrayWithSize.arrayWithSize import org.hamcrest.core.IsEqual.equalTo import org.hamcrest.core.Is.`is` as Is … val parts = intArrayOf(1, 2, 3) assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ arrayWithSize(3)) assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ Is(arrayWithSize(3))) assertThat(/* reason = */ "array has 3 elements", /* actual = */ parts, /* matcher = */ Is(arrayWithSize(equalTo(3))))
但仍然出现类型不匹配错误:
[ERROR] …/Decomposed_Test.kt:[287,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected [ERROR] …/Decomposed_Test.kt:[288,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>? was expected [ERROR] …/Decomposed_Test.kt:[288,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected [ERROR] …/Decomposed_Test.kt:[288,94] Type mismatch: inferred type is Matcher<Array<(out) (???..???)>!>! but Matcher<IntArray!>! was expected [ERROR] …/Decomposed_Test.kt:[289,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>? was expected [ERROR] …/Decomposed_Test.kt:[289,91] Type mismatch: inferred type is IntArray! but Array<(out) TypeVariable(E)!>! was expected [ERROR] …/Decomposed_Test.kt:[289,94] Type mismatch: inferred type is Matcher<Array<(out) (???..???)>!>! but Matcher<IntArray!>! was expected
问题原因
- 基本类型数组与对象数组的差异:Kotlin的
IntArray对应Java的int[](基本类型数组),而Hamcrest的arrayWithSize匹配器是为Java的对象数组Array<E>(对应Kotlin的Array<Int>)设计的,二者类型不兼容,匹配器无法识别IntArray。 - 重载解析混乱:最初的错误提示(要求String/Boolean)是因为Kotlin的重载解析机制优先匹配了
assertThat的其他重载方法(比如assertThat(String, Boolean)),而非我们需要的assertThat(T, Matcher<T>),导致错误提示偏离实际问题。
解决方案
方案1:转换为对象数组
将Kotlin的IntArray转换为Array<Int>(对应Java的Integer[]),即可直接使用原有Hamcrest匹配器:
val parts = intArrayOf(1, 2, 3).toTypedArray() // 之后原有三种断言写法均可正常运行 assertThat(parts, arrayWithSize(3)) assertThat(parts, Is(arrayWithSize(3))) assertThat(parts, Is(arrayWithSize(equalTo(3))))
方案2:自定义基本类型数组匹配器
如果不想转换数组类型,可以自定义针对IntArray的长度匹配器:
import org.hamcrest.BaseMatcher import org.hamcrest.Description import org.hamcrest.Matcher fun intArrayWithSize(size: Int): Matcher<IntArray> = object : BaseMatcher<IntArray>() { override fun matches(item: Any?): Boolean { return item is IntArray && item.size == size } override fun describeTo(description: Description?) { description?.appendText("int array with size $size") } } // 扩展支持匹配器嵌套 fun intArrayWithSize(sizeMatcher: Matcher<Int>): Matcher<IntArray> = object : BaseMatcher<IntArray>() { override fun matches(item: Any?): Boolean { return item is IntArray && sizeMatcher.matches(item.size) } override fun describeTo(description: Description?) { description?.appendText("int array with size ")?.appendDescriptionOf(sizeMatcher) } }
使用方式:
val parts = intArrayOf(1, 2, 3) assertThat(parts, intArrayWithSize(3)) assertThat(parts, Is(intArrayWithSize(3))) assertThat(parts, Is(intArrayWithSize(equalTo(3))))
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

