Przetestuj oczekiwane wyjątki w Kotlinie

90

W Javie programista może określić oczekiwane wyjątki dla przypadków testowych JUnit w następujący sposób:

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

Jak bym to zrobił w Kotlinie? Próbowałem dwóch odmian składni, ale żadna z nich nie działała:

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
źródło

Odpowiedzi:

125

Tłumaczenie Kotlin przykładu Java dla JUnit 4.12 to:

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

Jednak JUnit 4.13 wprowadził dwie assertThrowsmetody dla bardziej szczegółowych zakresów wyjątków:

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

Obie assertThrowsmetody zwracają oczekiwany wyjątek dla dodatkowych asercji:

@Test
fun omg() {
    // ...
    val exception = assertThrows(ArithmeticException::class.java) {
        val blackHole = 1 / 0
    }
    assertEquals("/ by zero", exception.message)
    // ...
}
fredoverflow
źródło
79

Kotlin ma własny pakiet pomocniczy do testów, który może pomóc w wykonaniu tego rodzaju unittest.

Twój test może być bardzo wyrazisty, używając assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Michele d'Amico
źródło
1
Jeśli otrzymasz 404 na swoim łączu, kotlin.testzostał zastąpiony przez coś innego?
fredoverflow
@fredoverflow Nie, nie jest zastępowany, ale po prostu usuwany z bibliotek standardowych. Zaktualizowałem link do repozytorium github kotlin, ale niestety nie mogę znaleźć żadnego linku do dokumentacji. W każdym razie jar jest dostarczany przez kotlin-plugin w intelliJ lub możesz go znaleźć w sieci lub dodać zależność maven / grandle do swojego projektu.
Michele d'Amico
7
kompiluj "org.jetbrains.kotlin: kotlin-test: $ kotlin_version"
mac229
4
@ mac229 s / compile / testCompile /
Laurence Gonsalves
@AshishSharma: kotlinlang.org/api/latest/kotlin.test/kotlin.test/ ... assertFail Zwróć wyjątek i możesz go użyć do napisania własnego potwierdzenia.
Michele d'Amico
26

Możesz użyć @Test(expected = ArithmeticException::class)lub nawet lepiej jednej z metod bibliotecznych Kotlin, takich jak failsWith().

Możesz go jeszcze skrócić, używając reified generics i metody pomocniczej, takiej jak ta:

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

I przykład z użyciem adnotacji:

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

}
Kirill Rakhman
źródło
javaClass<T>()jest teraz przestarzała. Użyj MyException::class.javazamiast tego.
fasth
failWith jest przestarzałe, zamiast tego należy użyć assertFailsWith .
gvlasov
15

Możesz do tego użyć KotlinTest .

W swoim teście możesz otoczyć dowolny kod blokiem shouldThrow:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
sksamuel
źródło
wydaje się, że to nie działa we właściwy sposób. Zaznaczam 1. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe true} - zielony 2. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe false} - zielony someMethod () throw "java .lang.AssertionError: message "kiedy powinien i zwróć obiekt, jeśli OK. W obu przypadkach powinnoThrow jest zielone, gdy OK, a gdy NIE.
Ivan Trechyokas
Może spójrz na dokumentację, mogło się to zmienić od czasu mojej odpowiedzi w 2016 roku. Github.com/kotlintest/kotlintest/blob/master/doc/…
sksamuel
13

JUnit5 ma wbudowaną obsługę 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 }
    }
}
Frank Neblung
źródło
3
To moja ulubiona odpowiedź. Jeśli dostaniesz się Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6na assertThrows, upewnij się, że Twój build.gradle macompileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
Big Pumpkin
11

Możesz także używać typów generycznych z pakietem kotlin.test:

import kotlin.test.assertFailsWith 

@Test
fun testFunction() {
    assertFailsWith<MyException> {
         // The code that will throw MyException
    }
}
Majid
źródło
1

Assert rozszerzenie, które weryfikuje klasę wyjątku, a także, jeśli komunikat o błędzie jest zgodny.

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

}

na przykład:

assertThrows<IllegalStateException>({
        throw IllegalStateException("fake error message")
    }, "fake error message")
Yanay Hollander
źródło
1

Nikt nie wspomniał, że assertFailsWith () zwraca wartość i możesz sprawdzić atrybuty wyjątku:

@Test
fun `my test`() {
        val exception = assertFailsWith<MyException> {method()}
        assertThat(exception.message, equalTo("oops!"))
    }
}
Svetopolk
źródło
0

Inna wersja składni używająca kluent :

@Test
fun `should throw ArithmeticException`() {
    invoking {
        val backHole = 1 / 0
    } `should throw` ArithmeticException::class
}
alexlz
źródło
0

Pierwszym krokiem jest dodanie (expected = YourException::class)adnotacji testowej

@Test(expected = YourException::class)

Drugim krokiem jest dodanie tej funkcji

private fun throwException(): Boolean = throw YourException()

W końcu będziesz miał coś takiego:

@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()
Cabezas
źródło
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)
Braian Coronel
źródło