Tester les exceptions attendues dans Kotlin

91

En Java, le programmeur peut spécifier des exceptions attendues pour les cas de test JUnit comme ceci:

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

Comment pourrais-je faire cela à Kotlin? J'ai essayé deux variantes de syntaxe, mais aucune d'elles n'a fonctionné:

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
la source

Réponses:

126

La traduction Kotlin de l'exemple Java pour JUnit 4.12 est:

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

Cependant, JUnit 4.13 a introduit deux assertThrowsméthodes pour les étendues d'exception plus fines:

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

Les deux assertThrowsméthodes renvoient l'exception attendue pour les assertions supplémentaires:

@Test
fun omg() {
    // ...
    val exception = assertThrows(ArithmeticException::class.java) {
        val blackHole = 1 / 0
    }
    assertEquals("/ by zero", exception.message)
    // ...
}
fredoverflow
la source
79

Kotlin a son propre package d'assistance de test qui peut aider à faire ce type de test unitt.

Votre test peut être très expressif en utilisant assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Michèle d'Amico
la source
1
Si obtenir un 404 sur votre lien, a kotlin.testété remplacé par autre chose?
fredoverflow
@fredoverflow Non, n'est pas remplacé, mais simplement supprimé des bibliothèques standard. J'ai mis à jour le lien vers le référentiel github kotlin mais malheureusement je ne trouve aucun lien vers la documentation. Quoi qu'il en soit, jar est livré par kotlin-plugin dans intelliJ ou vous pouvez le trouver sur le net ou ajouter une dépendance maven / grandle à votre projet.
Michele d'Amico
7
compilez "org.jetbrains.kotlin: kotlin-test: $ kotlin_version"
mac229
4
@ mac229 s / compile / testCompile /
Laurence Gonsalves
@AshishSharma: kotlinlang.org/api/latest/kotlin.test/kotlin.test/… assertFailWith renvoie l'exception et vous pouvez l'utiliser pour écrire votre propre assert.
Michele d'Amico
26

Vous pouvez utiliser @Test(expected = ArithmeticException::class)ou même mieux l'une des méthodes de bibliothèque de Kotlin comme failsWith().

Vous pouvez le rendre encore plus court en utilisant des génériques réifiés et une méthode d'aide comme celle-ci:

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

Et exemple utilisant l'annotation:

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

}
Kirill Rakhman
la source
javaClass<T>()est désormais obsolète. Utilisez MyException::class.javaplutôt.
Fasth
failWith est obsolète, assertFailsWith doit être utilisé à la place.
gvlasov
15

Vous pouvez utiliser KotlinTest pour cela.

Dans votre test, vous pouvez envelopper du code arbitraire avec un bloc shouldThrow:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
sksamuel
la source
semble en ligne, cela ne fonctionne pas correctement. Je vérifie 1. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe true} - vert 2. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe false} - vert someMethod () throw "java .lang.AssertionError: message "quand il le devrait, et renvoie objet si OK. Dans les deux cas, shouldThrow est vert quand OK et quand NON.
Ivan Trechyokas
Jetez peut-être un œil à la documentation, cela a peut-être changé depuis ma réponse en 2016. github.com/kotlintest/kotlintest/blob/master/doc/…
sksamuel
13

JUnit5 a un support kotlin intégré.

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
la source
3
C'est ma réponse préférée. Si vous obtenez Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6sur assertThrows, assurez-vous que votre build.gradle acompileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
Big Pumpkin
11

Vous pouvez également utiliser des génériques avec le package kotlin.test:

import kotlin.test.assertFailsWith 

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

Assert extension qui vérifie la classe d'exception et également si le message d'erreur correspond.

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

}

par exemple:

assertThrows<IllegalStateException>({
        throw IllegalStateException("fake error message")
    }, "fake error message")
Yanay Hollander
la source
1

Personne n'a mentionné que assertFailsWith () renvoie la valeur et vous pouvez vérifier les attributs d'exception:

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

Une autre version de la syntaxe utilise kluent :

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

La première étape consiste à ajouter une (expected = YourException::class)annotation de test

@Test(expected = YourException::class)

La deuxième étape consiste à ajouter cette fonction

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

Enfin, vous aurez quelque chose comme ceci:

@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
la source
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
la source