skip to content

assertFailsWith

assertFailsWith asserts that a block throws a specific type and hands the exception back so you can check its message and cause. Asserting on the exception rather than merely its type is what makes a failure test meaningful.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In kotlin.test, how do you assert that a block of code throws a specific exception type, and what does the assertion return?

level: juniorimportance: must knowfreq 70%

answer

  1. kotlin.test.assertFailsWith<T> { block }
  2. Returns the caught exception (typed T)
  3. Subtypes pass too
  4. Non-reified overload takes KClass
  5. Fails if nothing thrown or wrong type

basics

~20 s

Use assertFailsWith with the expected exception type and a lambda holding the code. The test passes only if that exception is thrown, and the call hands you back the caught exception so you can check it.

solid answer

~30 s

Call assertFailsWith<SomeException> { ... } from kotlin.test. The lambda is the code under test; the assertion passes only if it throws SomeException (or a subtype). It returns the caught exception instance, so you typically write `val ex = assertFailsWith<IllegalArgumentException> { parse(bad) }` and then assert on `ex.message`. If no exception is thrown, or a different type is thrown, the assertion fails with a clear message. There is also a non-reified overload `assertFailsWith(SomeException::class) { ... }`. This is the idiomatic, multiplatform way to test failures; it avoids the try/catch/fail pattern and works on JVM, JS, and Native.

code

kotlin · 16 lines
kotlin
import kotlin.test.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertEquals

class AgeTest {
    private fun setAge(a: Int): Int {
        require(a >= 0) { "age must be non-negative" }
        return a
    }

    @Test
    fun negativeAgeRejected() {
        val ex = assertFailsWith<IllegalArgumentException> { setAge(-1) }
        assertEquals("age must be non-negative", ex.message)
    }
}

go deeper

for a junior

Knows to call assertFailsWith<T> { ... } and that the test passes only when T is thrown.

for a middle

Captures the return value to assert on message, and knows subtypes match and there is a KClass overload.

for a senior

Frames it as the multiplatform-safe alternative to try/catch/fail and JUnit assertThrows, with consistent semantics across targets.

for a principal

Can articulate API design trade-offs (reified vs KClass, returning T for fluent follow-up) and guide team conventions for failure-path testing.

## What `assertFailsWith` does `assertFailsWith` is an assertion from the **`kotlin.test`** library (import `kotlin.test.assertFailsWith`). It verifies that executing a block of code throws an exception of an expected type. If the block does **not** throw, or throws a **different** type, the assertion fails. ## The reified generic form The common form uses a **reified type parameter** — `reified` means the generic type `T` is available at runtime, so you can write the exception type in angle brackets instead of passing a `Class`/`KClass`: ```kotlin import kotlin.test.assertFailsWith import kotlin.test.Test class ParserTest { @Test fun rejectsEmptyInput() { assertFailsWith<IllegalArgumentException> { require(false) { "empty" } } } } ``` ## It RETURNS the exception A key detail: `assertFailsWith` **returns the caught exception**, typed as `T`. Capture it to make further assertions: ```kotlin val ex = assertFailsWith<IllegalArgumentException> { parse("") } assertEquals("empty", ex.message) ``` The return type is exactly `T`, so `ex.message` and any type-specific properties are accessible without a cast. ## Subtypes count The match is **assignment-compatible**: throwing a subtype of `T` passes. `assertFailsWith<RuntimeException> { throw IllegalStateException() }` succeeds because `IllegalStateException` is a `RuntimeException`. ## Non-reified overload When you only have a `KClass` (e.g. computed at runtime), use `assertFailsWith(exceptionClass: KClass<T>, block)`: ```kotlin assertFailsWith(IllegalStateException::class) { check(false) } ``` ## Summary - Import from `kotlin.test`, not JUnit. - Reified form: `assertFailsWith<T> { ... }`. - Passes on `T` or any subtype; fails on no-throw or wrong type. - Returns the exception `T` for follow-up assertions.

  • What happens if the block does not throw anything?
    The assertion fails with a message saying an exception of the expected type was expected but the block completed normally.
  • Does it pass if a subclass of the expected exception is thrown?
    Yes. The match is assignment-compatible, so any subtype of the declared type satisfies it.

Like setting a specific mousetrap: it only counts as a catch if the right animal (exception type) springs it, and you get to inspect what you caught.

saying these in an interview costs you the question

  • Thinking it comes from JUnit's Assertions class instead of kotlin.test
  • Not knowing it returns the exception, so wrapping it in try/catch to grab the message
  • Believing only the exact type passes, not subtypes
  • Confusing it with assertThrows/expected= annotations

context

open as a page

Show how to use the value returned by assertFailsWith to assert on an exception's message and its cause.

level: middleimportance: must knowfreq 60%

basics

~10 s

Capture the returned exception in a variable. Then check its message with assertEquals or assertContains, and check its cause by reading ex.cause, asserting its type and message too.

open as a page

What is the difference between assertFails and assertFailsWith in kotlin.test, and when would you choose each?

level: middleimportance: should knowfreq 55%

basics

~10 s

assertFails only checks that something was thrown, ignoring the type, and returns the Throwable. assertFailsWith checks for a specific type. Use assertFails when any failure is fine; use assertFailsWith when the exact exception matters.

open as a page

How do you assert that a suspend function throws a specific exception, and what subtle issues arise with assertFailsWith and coroutines?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Run the suspend call inside runTest (or runBlocking) and put it in the assertFailsWith lambda. Be careful: the lambda is not a suspend lambda by default, so call the suspend function from within a coroutine scope.

open as a page

Across the kotlin.test multiplatform API, how does assertFailsWith stay portable, and how does it compare to JUnit's assertThrows when running on the JVM?

level: seniorimportance: nice to knowfreq 28%

basics

~10 s

assertFailsWith is part of kotlin.test, so the same test code runs on JVM, JS, and Native. JUnit's assertThrows is JVM-only. Both check a thrown type and return the exception, but only kotlin.test is multiplatform.

open as a page