在 Kotlin 测试预期的例外情况

在 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 ')'
82513 次浏览

你可以使用 @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() {


}

用于 JUnit 4.12的 Java 示例的 Kotlin 翻译如下:

@Test(expected = ArithmeticException::class)
fun omg() {
val blackHole = 1 / 0
}

然而,JUnit 4.13 介绍两个用于细粒度异常作用域的 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)
// ...
}

Kotlin 有自己的 test helper 包 ,可以帮助进行这种单元测试。

通过使用 assertFailWith,你的测试可以非常有表现力:

@Test
fun test_arithmethic() {
assertFailsWith<ArithmeticException> {
omg()
}
}

您可以使用 Kotest进行此操作。

在您的测试中,您可以将任意代码包装为 should dthrow 块:

shouldThrow<ArithmeticException> {
// code in here that you expect to throw a ArithmeticException
}

您还可以在 kotlin.test 包中使用泛型:

import kotlin.test.assertFailsWith


@Test
fun testFunction() {
assertFailsWith<MyException> {
// The code that will throw MyException
}
}

JUnit5内置 Kotlin 的支持

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 }
}
}

使用 干净利落的另一种形式的句法:

@Test
fun `should throw ArithmeticException`() {
invoking {
val backHole = 1 / 0
} `should throw` ArithmeticException::class
}

断言验证异常类以及错误消息是否匹配的扩展名。

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")

第一步是在测试注释中添加 (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()

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)

没有人提到 assertFailsWith ()返回值,您可以检查异常属性:

@Test
fun `my test`() {
val exception = assertFailsWith<MyException> {method()}
assertThat(exception.message, equalTo("oops!"))
}
}

这个简单的示例在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)
}