Teste as exceções esperadas em Kotlin

94

Em Java, o programador pode especificar as exceções esperadas para casos de teste JUnit como este:

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

Como eu faria isso em Kotlin? Eu tentei duas variações de sintaxe, mas nenhuma delas funcionou:

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
fonte

Respostas:

129

A tradução Kotlin do exemplo Java para JUnit 4.12 é:

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

No entanto, JUnit 4.13 introduziu dois assertThrowsmétodos para escopos de exceção mais granulares:

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

Ambos os assertThrowsmétodos retornam a exceção esperada para afirmações adicionais:

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

Kotlin tem seu próprio pacote auxiliar de teste que pode ajudar a fazer esse tipo de teste de unidade.

Seu teste pode ser muito expressivo usando assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Michele d'Amico
fonte
1
Se obtiver um 404 no seu link, kotlin.testfoi substituído por outro?
fredoverflow
@fredoverflow Não, não é substituído, mas apenas removido das bibliotecas padrão. Atualizei o link para o repositório github kotlin, mas infelizmente não consigo encontrar nenhum link para a documentação. De qualquer forma, o jar é fornecido pelo plugin kotlin no intelliJ ou você pode encontrá-lo na rede ou adicionar a dependência maven / grandle ao seu projeto.
Michele d'Amico
7
compilar "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 retorna a exceção e você pode usá-lo para escrever sua própria declaração.
Michele d'Amico
26

Você pode usar @Test(expected = ArithmeticException::class)ou ainda melhor um dos métodos de biblioteca de Kotlin como failsWith().

Você pode torná-lo ainda mais curto usando genéricos reificados e um método auxiliar como este:

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

E um exemplo usando a anotação:

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

}
Kirill Rakhman
fonte
javaClass<T>()está obsoleto agora. Use em seu MyException::class.javalugar.
dia
failWith está obsoleto, assertFailsWith deve ser usado em seu lugar.
gvlasov
15

Você pode usar o KotlinTest para isso.

Em seu teste, você pode encapsular código arbitrário com um bloco shouldThrow:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
sksamuel
fonte
parece linha que não funciona de maneira adequada. Eu verifico 1. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe true} - verde 2. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe false} - verde someMethod () throw "java .lang.AssertionError: message "quando deveria, e retornar o objeto se estiver OK. Em ambos os casos, o shouldThrow fica verde quando está OK e quando NÃO.
Ivan Trechyokas
Talvez dê uma olhada na documentação, pode ter mudado desde minha resposta em 2016. github.com/kotlintest/kotlintest/blob/master/doc/…
sksamuel
13

JUnit5 possui suporte a kotlin integrado.

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
fonte
3
Esta é minha resposta preferida. Se você Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6acessar assertThrows, certifique-se de que seu build.gradle tenhacompileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
Big Pumpkin
11

Você também pode usar genéricos com o pacote kotlin.test:

import kotlin.test.assertFailsWith 

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

Assert extensão que verifica a classe de exceção e também se a mensagem de erro corresponde.

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

}

por exemplo:

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

Ninguém mencionou que assertFailsWith () retorna o valor e você pode verificar os atributos de exceção:

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

Outra versão da sintaxe usando kluent :

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

As primeiras etapas são adicionar uma (expected = YourException::class)anotação de teste

@Test(expected = YourException::class)

A segunda etapa é adicionar esta função

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

Finalmente, você terá algo assim:

@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
fonte
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
fonte