Uji pengecualian yang diharapkan di Kotlin

91

Di Java, programmer dapat menentukan pengecualian yang diharapkan untuk kasus uji JUnit seperti ini:

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

Bagaimana saya melakukan ini di Kotlin? Saya telah mencoba dua variasi sintaks, tetapi tidak ada yang berhasil:

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
sumber

Jawaban:

126

Terjemahan Kotlin dari contoh Java untuk JUnit 4.12 adalah:

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

Namun, JUnit 4.13 memperkenalkan dua assertThrowsmetode untuk cakupan pengecualian yang lebih terperinci:

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

Kedua assertThrowsmetode mengembalikan pengecualian yang diharapkan untuk pernyataan tambahan:

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

Kotlin memiliki paket pembantu pengujiannya sendiri yang dapat membantu melakukan jenis unittest ini.

Tes Anda bisa sangat ekspresif dengan menggunakan assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Michele d'Amico
sumber
1
Jika mendapatkan 404 pada link Anda, apakah kotlin.testtelah diganti dengan yang lain?
fredoverflow
@fredoverflow Tidak, tidak diganti, tetapi baru saja dihapus dari pustaka standar. Saya telah memperbarui tautan ke repositori github kotlin tetapi sayangnya saya tidak dapat menemukan tautan apa pun ke dokumentasi. Anyway jar dikirimkan oleh kotlin-plugin di intelliJ atau Anda dapat menemukannya di internet atau menambahkan ketergantungan maven / grandle ke proyek Anda.
Michele d'Amico
7
kompilasi "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 mengembalikan pengecualian dan Anda dapat menggunakannya untuk menulis assert Anda sendiri.
Michele d'Amico
26

Anda dapat menggunakan @Test(expected = ArithmeticException::class)atau bahkan lebih baik dari salah satu metode library Kotlin seperti failsWith().

Anda dapat membuatnya lebih pendek dengan menggunakan obat generik yang telah direifikasi dan metode pembantu seperti ini:

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

Dan contoh menggunakan anotasi:

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

}
Kirill Rakhman
sumber
javaClass<T>()sudah usang sekarang. Gunakan MyException::class.javasebagai gantinya.
puasa
FailWith tidak digunakan lagi, assertFailsWith harus digunakan sebagai gantinya.
gvlasov
15

Anda dapat menggunakan KotlinTest untuk ini.

Dalam pengujian Anda, Anda dapat membungkus kode arbiter dengan blok shouldThrow:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
sksamuel.dll
sumber
Sepertinya garis itu tidak bekerja dengan cara yang benar. Saya centang 1. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe true} - green 2. shouldThrow <java.lang.AssertionError> {someMethod (). IsOK shouldBe false} - green someMethod () throw "java .lang.AssertionError: message "jika seharusnya, dan mengembalikan objek jika OK. Dalam kedua kasus, shouldThrow berwarna hijau saat OK dan saat TIDAK.
Ivan Trechyokas
Mungkin lihat dokumentasinya, mungkin sudah berubah sejak jawaban saya di 2016. github.com/kotlintest/kotlintest/blob/master/doc/…
sksamuel
13

JUnit5 memiliki dukungan kotlin bawaan .

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
sumber
3
Ini adalah jawaban pilihan saya. Jika Anda mendapatkan Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6assertThrows, pastikan build.gradle Anda memilikicompileTestKotlin { kotlinOptions.jvmTarget = "1.8" }
Big Pumpkin
11

Anda juga dapat menggunakan obat generik dengan paket kotlin.test:

import kotlin.test.assertFailsWith 

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

Tegaskan ekstensi yang memverifikasi kelas pengecualian dan juga jika pesan kesalahan cocok.

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

}

sebagai contoh:

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

Tidak ada yang menyebutkan bahwa assertFailsWith () mengembalikan nilai dan Anda dapat memeriksa atribut pengecualian:

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

Versi lain dari sintaksis menggunakan kluent :

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

Langkah pertama adalah menambahkan (expected = YourException::class)anotasi tes

@Test(expected = YourException::class)

Langkah kedua adalah menambahkan fungsi ini

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

Akhirnya Anda akan mendapatkan sesuatu seperti ini:

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