如何在Kotlin中测试预期未检查异常?解决assertThrows类型推断问题
解决Kotlin中JUnit 5测试未检查异常的类型推断问题
别担心,这个问题其实很常见——因为Kotlin对未检查异常(比如RuntimeException子类)的类型推断逻辑和检查异常不一样,直接用assertThrows会让编译器摸不清你要捕获的具体异常类型。不过完全不用退回到try-catch,只要给assertThrows显式指定泛型类型就能搞定!
正确的用法示例
假设你要测试的函数会抛出自定义的MyRuntimeException,可以这么写:
import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test class ExceptionTest { @Test fun `should throw custom runtime exception on invalid action`() { // 显式指定要捕获的异常类型作为泛型参数 val thrownException = assertThrows<MyRuntimeException> { // 这里放会触发异常的代码 doInvalidAction() } // 还可以额外验证异常的细节,比如错误消息 assert(thrownException.message == "Invalid action performed!") } private fun doInvalidAction() { throw MyRuntimeException("Invalid action performed!") } } class MyRuntimeException(message: String) : RuntimeException(message)
如果只是要捕获通用的RuntimeException,写法也类似:
@Test fun `should throw generic runtime exception`() { assertThrows<RuntimeException> { throw RuntimeException("Oops!") } }
为什么之前会失败?
Kotlin编译器没办法从抛出异常的lambda里自动推断出assertThrows需要的异常类型——毕竟lambda本身没有正常的返回值,只有异常抛出。显式指定泛型参数相当于给编译器一个明确的提示,告诉它“我要捕获这个类型的异常”,这样就能顺利通过编译,还能拿到异常实例做后续验证。
这种方式完全符合JUnit 5的设计规范,比try-catch更简洁,也更易读,还能直接利用断言库的能力。
内容的提问来源于stack exchange,提问作者Marcus Lanvers
相关产品推荐
相关产品推荐

