147

In Java, the programmer can specify expected exceptions for JUnit test cases like this:

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

How would I do this in Kotlin? I have tried two syntax variations, but none of them worked:

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
  • 256,549
  • 94
  • 388
  • 662

12 Answers12

194

The Kotlin translation of the Java example for JUnit 4.12 is:

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

However, JUnit 4.13 introduced two assertThrows methods for finer-granular exception scopes:

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

Both assertThrows methods return the expected exception for additional assertions:

@Test
fun omg() {
    // ...
    val exception = assertThrows(ArithmeticException::class.java) {
        val blackHole = 1 / 0
    }
    assertEquals("/ by zero", exception.message)
    // ...
}
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
122

Kotlin has its own test helper package that can help to do this kind of unittest.

Your test can be very expressive by use assertFailWith:

@Test
fun test_arithmethic() {
    assertFailsWith<ArithmeticException> {
        omg()
    }
}
Michele d'Amico
  • 22,111
  • 8
  • 69
  • 76
  • 1
    If get a 404 on your link, has `kotlin.test` been replaced by something else? – fredoverflow May 25 '17 at 06:59
  • @fredoverflow No, is not replaced, but just removed from standard libraries. I've updated link to github kotlin repository but unfortunately I cannot find any link to documentation. Anyway jar is shipped by kotlin-plugin in intelliJ or you can find it on the net or add maven/grandle dependency to your project. – Michele d'Amico May 25 '17 at 08:37
  • 8
    compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" – mac229 Sep 21 '17 at 20:06
  • 4
    @mac229 s/compile/testCompile/ – Laurence Gonsalves Mar 16 '18 at 16:36
  • @AshishSharma : https://kotlinlang.org/api/latest/kotlin.test/kotlin.test/assert-fails-with.html assertFailWith return the exception and you can use it to write your own assert. – Michele d'Amico Jun 17 '20 at 06:32
  • I manage to that like below. But If anybody can provide me an example how can i check for exception type in case of completablefutue because it wrapped actual exception class . var exception = assertFailsWith(CustomException::class) { someclass.somemethod(arg) } Assertions.assertEquals("some message", exception.localizedMessage) – Ashish Sharma Jun 18 '20 at 18:29
29

You can use @Test(expected = ArithmeticException::class) or even better one of Kotlin's library methods like failsWith().

You can make it even shorter by using reified generics and a helper method like this:

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

And example using the annotation:

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

}
Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148
  • `javaClass()` is deprecated now. Use `MyException::class.java` instead. – fasth Oct 28 '15 at 09:21
  • 1
    failsWith is deprecated, [assertFailsWith](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.test/assert-fails-with.html) should be used instead. – gvlasov Nov 13 '15 at 05:25
22

You can use Kotest for this.

In your test, you can wrap arbitrary code with a shouldThrow block:

shouldThrow<ArithmeticException> {
  // code in here that you expect to throw a ArithmeticException
}
sksamuel
  • 16,154
  • 8
  • 60
  • 108
  • seems line it doesn't work in proper way. I check 1. shouldThrow { someMethod().isOK shouldBe true } - green 2. shouldThrow { someMethod().isOK shouldBe false } - green someMethod() throw "java.lang.AssertionError: message" when it should, and return object if OK. In both cases shouldThrow is green when OK and when NOT. – Ivan Trechyokas Nov 06 '18 at 07:22
  • Maybe take a look at the docs, it might have changed since my answer in 2016. https://github.com/kotlintest/kotlintest/blob/master/doc/reference.md#exceptions – sksamuel Nov 07 '18 at 08:04
18

JUnit5 has kotlin support built in.

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
  • 3,047
  • 17
  • 34
  • 3
    This is my preferred answer. If you get `Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6` on assertThrows, make sure your build.gradle has `compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }` – Big Pumpkin Dec 09 '19 at 05:22
16

You can also use generics with kotlin.test package:

import kotlin.test.assertFailsWith 

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

Nobody mentioned that assertFailsWith() returns the value and you can check exception attributes:

@Test
fun `my test`() {
        val exception = assertFailsWith<MyException> {method()}
        assertThat(exception.message, equalTo("oops!"))
    }
}
Svetopolk
  • 337
  • 5
  • 14
4

This simple sample worked in the 4.13.2 version of Junit

    @Test
    fun testZeroDividing(){
        var throwing = ThrowingRunnable {  /*call your method here*/ Calculator().divide(1,0) }
        assertThrows(/*define your exception here*/ IllegalArgumentException::class.java, throwing)
    }
Ali Doran
  • 378
  • 1
  • 12
3

Assert extension that verifies the exception class and also if the error message match.

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

}

for example:

assertThrows<IllegalStateException>({
        throw IllegalStateException("fake error message")
    }, "fake error message")
Yanay Hollander
  • 327
  • 1
  • 5
  • 19
2

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
  • 22,105
  • 4
  • 57
  • 62
0

Another version of syntaxis using kluent:

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

Firt steps is to add (expected = YourException::class) in test annotation

@Test(expected = YourException::class)

Second step is to add this function

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

Finally you will have something like this:

@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
  • 9,329
  • 7
  • 67
  • 69