Тестирование ожидаемых исключений в Котлине

94

В Java программист может указать ожидаемые исключения для тестовых случаев JUnit следующим образом:

@Test(expected = ArithmeticException.class)
public void omg()
{
    int blackHole = 1 / 0;
}

Как бы я сделал это в Котлине? Я пробовал два варианта синтаксиса, но ни один из них не работал:

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 ')'
fredoverflow
источник

Ответы:

129

Перевод примера Java для JUnit 4.12 на 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)
    // ...
}
fredoverflow
источник
83

У Kotlin есть собственный пакет вспомогательных средств тестирования, который может помочь в проведении такого рода модульного тестирования.

Ваш тест может быть очень выразительным, если использовать assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Микеле д'Амико
источник
1
Если получилось 404 по вашей ссылке, kotlin.testбыло заменено на что-то другое?
fredoverflow
@fredoverflow Нет, не заменяется, а просто удаляется из стандартных библиотек. Я обновил ссылку на репозиторий github kotlin, но, к сожалению, я не могу найти ссылку на документацию. В любом случае jar поставляется kotlin-plugin в intelliJ, или вы можете найти его в сети или добавить зависимость maven / grandle в свой проект.
Michele d'Amico
7
скомпилировать "org.jetbrains.kotlin: kotlin-test: $ kotlin_version"
mac229
4
@ mac229 s / compile / testCompile /
Лоуренс Гонсалвес
@AshishSharma: kotlinlang.org/api/latest/kotlin.test/kotlin.test/… assertFailWith возвращает исключение, и вы можете использовать его для написания собственного утверждения.
Michele d'Amico
26

Вы можете использовать @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 .
gvlasov
15

Для этого вы можете использовать KotlinTest .

В вашем тесте вы можете заключить произвольный код в блок shouldThrow:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
Sksamuel
источник
кажется, линия не работает должным образом. Я проверяю 1. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe true} - зеленый 2. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe false} - зеленый someMethod () throw "java .lang.AssertionError: message "когда должно, и вернуть объект, если ОК. В обоих случаях shouldThrow горит зеленым, когда ОК, а когда НЕ.
Иван Тречёкас
Может принимать взглянуть на документы, он может быть изменен с момента моего ответа в 2016 году github.com/kotlintest/kotlintest/blob/master/doc/...
sksamuel
13

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
Это мой предпочтительный ответ. Если вы попадаете Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6на assertThrows, убедитесь, что в вашем build.gradle естьcompileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
Big Pumpkin
11

Вы также можете использовать дженерики с пакетом kotlin.test:

import kotlin.test.assertFailsWith 

@Test
fun testFunction() {
    assertFailsWith<MyException> {
         // The code that will throw MyException
    }
}
Маджид
источник
1

Расширение Assert, которое проверяет класс исключения, а также соответствие сообщения об ошибке.

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")
Янай Холландер
источник
1

Никто не упомянул, что assertFailsWith () возвращает значение, и вы можете проверить атрибуты исключения:

@Test
fun `my test`() {
        val exception = assertFailsWith<MyException> {method()}
        assertThat(exception.message, equalTo("oops!"))
    }
}
Светополк
источник
0

Другая версия синтаксиса с использованием kluent :

@Test
fun `should throw ArithmeticException`() {
    invoking {
        val backHole = 1 / 0
    } `should throw` ArithmeticException::class
}
Alexlz
источник
0

Первые шаги - добавить (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()
Кабесас
источник
0

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)
Брайан Коронел
источник