在 Kotlin 中测试预期的异常
Posted
技术标签:
【中文标题】在 Kotlin 中测试预期的异常【英文标题】:Test expected exceptions in Kotlin 【发布时间】:2015-07-31 15:30:18 【问题描述】:在 Java 中,程序员可以像这样为 JUnit 测试用例指定预期的异常:
@Test(expected = ArithmeticException.class)
public void omg()
int blackHole = 1 / 0;
我将如何在 Kotlin 中执行此操作?我尝试了两种语法变体,但都没有奏效:
import org.junit.Test
// ...
@Test(expected = ArithmeticException) fun omg()
Please specify constructor invocation;
classifier 'ArithmeticException' does not have a companion object
@Test(expected = ArithmeticException.class) fun omg()
name expected ^
^ expected ')'
【问题讨论】:
【参考方案1】:JUnit 4.12 的 Java 示例的 Kotlin 翻译为:
@Test(expected = ArithmeticException::class)
fun omg()
val blackHole = 1 / 0
但是,JUnit 4.13 introduced 两个 assertThrows
方法用于更细粒度的异常范围:
@Test
fun omg()
// ...
assertThrows(ArithmeticException::class.java)
val blackHole = 1 / 0
// ...
两个assertThrows
方法都返回预期的额外断言异常:
@Test
fun omg()
// ...
val exception = assertThrows(ArithmeticException::class.java)
val blackHole = 1 / 0
assertEquals("/ by zero", exception.message)
// ...
【讨论】:
【参考方案2】:Kotlin has its own test helper package 可以帮助进行这种单元测试。
使用assertFailWith
,您的测试可以非常有表现力:
@Test
fun test_arithmethic()
assertFailsWith<ArithmeticException>
omg()
【讨论】:
如果您的链接出现 404,kotlin.test
是否已被其他内容替换?
@fredoverflow 不,不会被替换,只是从标准库中删除。我已经更新了 github kotlin 存储库的链接,但不幸的是我找不到任何文档链接。无论如何 jar 是由 intelliJ 中的 kotlin-plugin 提供的,或者您可以在网上找到它或将 maven/grandle 依赖项添加到您的项目中。
编译“org.jetbrains.kotlin:kotlin-test:$kotlin_version”
@mac229 s/compile/testCompile/
@AshishSharma : kotlinlang.org/api/latest/kotlin.test/kotlin.test/…assertFailWith 返回异常,您可以使用它来编写自己的断言。【参考方案3】:
您可以使用 @Test(expected = ArithmeticException::class)
或者甚至更好的 Kotlin 库方法之一,例如 failsWith()
。
您可以通过使用具体的泛型和这样的辅助方法来缩短它:
inline fun <reified T : Throwable> failsWithX(noinline block: () -> Any)
kotlin.test.failsWith(javaClass<T>(), block)
以及使用注释的示例:
@Test(expected = ArithmeticException::class)
fun omg()
【讨论】:
javaClass<T>()
现已弃用。请改用MyException::class.java
。
failsWith 已弃用,应使用assertFailsWith。【参考方案4】:
您可以为此使用Kotest。
在您的测试中,您可以使用 shouldThrow 块包装任意代码:
shouldThrow<ArithmeticException>
// code in here that you expect to throw a ArithmeticException
【讨论】:
似乎行它不能以正确的方式工作。我检查 1. shouldThrowJUnit5 内置了kotlin support。
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
class MyTests
@Test
fun `division by zero -- should throw ArithmeticException`()
assertThrows<ArithmeticException> 1 / 0
【讨论】:
这是我的首选答案。如果您在 assertThrows 上收到Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6
,请确保您的 build.gradle 有 compileTestKotlin kotlinOptions.jvmTarget = "1.8"
【参考方案6】:
您还可以在 kotlin.test 包中使用泛型:
import kotlin.test.assertFailsWith
@Test
fun testFunction()
assertFailsWith<MyException>
// The code that will throw MyException
【讨论】:
【参考方案7】:没有人提到 assertFailsWith() 返回值,你可以检查异常属性:
@Test
fun `my test`()
val exception = assertFailsWith<MyException> method()
assertThat(exception.message, equalTo("oops!"))
【讨论】:
【参考方案8】:验证异常类以及错误消息是否匹配的断言扩展。
inline fun <reified T : Exception> assertThrows(runnable: () -> Any?, message: String?)
try
runnable.invoke()
catch (e: Throwable)
if (e is T)
message?.let
Assert.assertEquals(it, "$e.message")
return
Assert.fail("expected $T::class.qualifiedName but caught " +
"$e::class.qualifiedName instead")
Assert.fail("expected $T::class.qualifiedName")
例如:
assertThrows<IllegalStateException>(
throw IllegalStateException("fake error message")
, "fake error message")
【讨论】:
【参考方案9】:org.junit.jupiter.api.Assertions.kt
/**
* Example usage:
* ```kotlin
* val exception = assertThrows<IllegalArgumentException>("Should throw an Exception")
* throw IllegalArgumentException("Talk to a duck")
*
* assertEquals("Talk to a duck", exception.message)
* ```
* @see Assertions.assertThrows
*/
inline fun <reified T : Throwable> assertThrows(message: String, noinline executable: () -> Unit): T =
assertThrows( message , executable)
【讨论】:
【参考方案10】:另一个版本的语法使用kluent:
@Test
fun `should throw ArithmeticException`()
invoking
val backHole = 1 / 0
`should throw` ArithmeticException::class
【讨论】:
【参考方案11】:第一步是在测试注释中添加(expected = YourException::class)
@Test(expected = YourException::class)
第二步是添加这个功能
private fun throwException(): Boolean = throw YourException()
最后你会得到这样的东西:
@Test(expected = ArithmeticException::class)
fun `get query error from assets`()
//Given
val error = "ArithmeticException"
//When
throwException()
val result = omg()
//Then
Assert.assertEquals(result, error)
private fun throwException(): Boolean = throw ArithmeticException()
【讨论】:
【参考方案12】:这个简单的示例在 4.13.2 版本的 Junit 中工作
@Test
fun testZeroDividing()
var throwing = ThrowingRunnable /*call your method here*/ Calculator().divide(1,0)
assertThrows(/*define your exception here*/ IllegalArgumentException::class.java, throwing)
【讨论】:
以上是关于在 Kotlin 中测试预期的异常的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin-multiplatform:如何执行 iOS 单元测试
称为验证的 Mockito Kotlin 单元测试方法抛出空指针异常
Kotlin 协程单元测试错误:线程“main @coroutine#1 @coroutine#2”中的异常 java.lang.NullPointerException
KotlinKotlin 与 Java 互操作 ③ ( Kotlin 中处理 Java 异常 | Java 中处理 Kotlin 异常 | @Throws 注解处理异常 | 函数类型互相操作 )