在 Kotlin 中测试预期异常

Test expected exceptions in Kotlin

提问人:fredoverflow 提问时间:5/20/2015 最后编辑:fredoverflow 更新时间:12/2/2021 访问量:101820

问:

在 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 ')'
单元测试 Kotlin 测试 异常 junit4

评论


答:

29赞 Kirill Rakhman 5/20/2015 #1

您可以使用甚至更好的 Kotlin 库方法之一,例如 failsWith()。@Test(expected = ArithmeticException::class)

你可以通过使用具体化的泛型和如下所示的帮助程序方法来使其更短:

inline fun <reified T : Throwable> failsWithX(noinline block: () -> Any) {
    kotlin.test.failsWith(javaClass<T>(), block)
}

并使用注释的示例:

@Test(expected = ArithmeticException::class)
fun omg() {

}

评论

0赞 fasth 10/28/2015
javaClass<T>()现已弃用。请改用。MyException::class.java
1赞 gvlasov 11/13/2015
failsWith 已弃用,应改用 assertFailsWith
200赞 fredoverflow 6/1/2015 #2

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)
    // ...
}
123赞 Michele d'Amico 1/1/2016 #3

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

通过使用以下方法,您的测试可以非常富有表现力:assertFailWith

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

评论

1赞 fredoverflow 5/25/2017
如果您的链接上有 404,已被其他东西取代?kotlin.test
0赞 Michele d'Amico 5/25/2017
@fredoverflow 否,不会被替换,只是从标准库中删除。我已经更新了 github kotlin 存储库的链接,但不幸的是我找不到任何文档链接。无论如何,jar 是由 intelliJ 中的 kotlin-plugin 提供的,或者你可以在网上找到它,或者将 maven/grandle 依赖项添加到你的项目中。
8赞 mac229 9/22/2017
编译“org.jetbrains.kotlin:kotlin-test:$kotlin_version”
4赞 Laurence Gonsalves 3/17/2018
@mac229 s/compile/testCompile/
0赞 Michele d'Amico 6/17/2020
@AshishSharma : kotlinlang.org/api/latest/kotlin.test/kotlin.test/... assertFailWith 返回异常,你可以用它来编写你自己的断言。
23赞 sksamuel 5/12/2016 #4

您可以使用Kotest

在测试中,您可以使用 shouldThrow 块包装任意代码:

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

评论

0赞 Ivan Trechyokas 11/6/2018
似乎行它没有以正确的方式工作。我检查 1。shouldThrow<java.lang.AssertionError> { someMethod().isOK shouldBe true } - 绿色 2.shouldThrow<java.lang.AssertionError> { someMethod().isOK shouldBe false } - 绿色 someMethod() 在应该抛出 “java.lang.AssertionError: message” 的时候抛出,如果 OK 则返回对象。在这两种情况下,shouldThrow 在 OK 和 NOT 时均为绿色。
0赞 sksamuel 11/7/2018
也许看看文档,自从我在 2016 年回答以来,它可能已经改变了。github.com/kotlintest/kotlintest/blob/master/doc/......
16赞 Majid 3/30/2018 #5

您还可以将泛型与 kotlin.test 包一起使用:

import kotlin.test.assertFailsWith 

@Test
fun testFunction() {
    assertFailsWith<MyException> {
         // The code that will throw MyException
    }
}
18赞 Frank Neblung 7/20/2018 #6

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

评论

3赞 Big Pumpkin 12/9/2019
这是我的首选答案。如果你使用 assertThrows,请确保你的 build.gradle 有Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
0赞 alexlz 2/13/2020 #7

另一个版本的语法使用 kluent

@Test
fun `should throw ArithmeticException`() {
    invoking {
        val backHole = 1 / 0
    } `should throw` ArithmeticException::class
}
3赞 Yanay Hollander 5/7/2020 #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")
0赞 Cabezas 8/18/2020 #9

第一个步骤是添加测试注解(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()
2赞 Braian Coronel 9/30/2020 #10

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)
7赞 Svetopolk 10/7/2020 #11

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

@Test
fun `my test`() {
        val exception = assertFailsWith<MyException> {method()}
        assertThat(exception.message, equalTo("oops!"))
    }
}
4赞 Ali Doran 12/2/2021 #12

这个简单的示例适用于 Junit 的 4.13.2 版本

    @Test
    fun testZeroDividing(){
        var throwing = ThrowingRunnable {  /*call your method here*/ Calculator().divide(1,0) }
        assertThrows(/*define your exception here*/ IllegalArgumentException::class.java, throwing)
    }