如何在Java AssertJ中实现Kotlin扩展函数校验自定义异常code属性?
解决AssertJ Kotlin扩展函数获取异常实例的问题
要搞定这个问题,核心是你可能不知道ThrowableAssertAlternative本身就提供了公开的actual属性,直接就能拿到实际抛出的异常对象,不需要绕弯子。下面给你两种实用的实现方案:
方案1:针对MyException的专属扩展函数
既然你已经用assertThatExceptionOfType(MyException::class.java)指定了异常类型,那完全可以写一个针对性的扩展函数,省去类型转换的麻烦:
// 直接限定为MyException的断言类型,不用泛型兼容所有Throwable private fun ThrowableAssertAlternative<MyException>.withErrorCode(expectedErrorCode: Int): ThrowableAssertAlternative<MyException> { // 直接通过actual拿到MyException实例,校验code属性 assertThat(this.actual.code) .isEqualTo(expectedErrorCode) // 返回this保证链式调用的连贯性 return this }
你的测试代码可以直接按预期使用:
@Test fun `Creating webdto without name fails`() { assertThatExceptionOfType(MyException::class.java) .isThrownBy { service.create(WebDto.apply { this.name = null }) } .withMessageContaining("Bean validation error.") .withErrorCode(1) // 现在能正常校验code了 }
方案2:通用扩展函数(支持所有带code的异常)
如果你的项目里有多个自定义异常都带code属性,可以先定义统一接口,再写通用扩展函数,扩展性更强:
首先定义接口并让MyException实现它:
interface CodedException { val code: Int } // 修改MyException实现该接口 class MyException: Exception, CodedException { override val code: Int constructor(message: String, code: Int) : super(message) { this.code = code } constructor(cause: Throwable, code: Int) : super(cause) { this.code = code } }
然后编写通用扩展函数:
private fun <T : Throwable> ThrowableAssertAlternative<T>.withErrorCode(expectedErrorCode: Int): ThrowableAssertAlternative<T> { // 把实际异常转换为CodedException,转换失败时抛出清晰的断言错误 val codedException = this.actual as? CodedException ?: failWithMessage("Expected exception to implement CodedException, but got ${actual?.javaClass?.simpleName}") assertThat(codedException.code) .isEqualTo(expectedErrorCode) return this }
这种方式能支持所有实现了CodedException接口的异常,复用性拉满。
关键提示
ThrowableAssertAlternative的actual属性是公开可用的,在Kotlin扩展函数里直接用this.actual就能拿到抛出的异常实例。- 要保持链式调用,扩展函数必须返回
this,这样就能和AssertJ原有的断言方法连贯使用。
内容的提问来源于stack exchange,提问作者Manu Zi
相关产品推荐
相关产品推荐

