In kotlin.test, how do you assert that a block of code throws a specific exception type, and what does the assertion return?
answer
- kotlin.test.assertFailsWith<T> { block }
- Returns the caught exception (typed T)
- Subtypes pass too
- Non-reified overload takes KClass
- Fails if nothing thrown or wrong type
basics
~20 sUse 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 sCall 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 linesimport 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
Knows to call assertFailsWith<T> { ... } and that the test passes only when T is thrown.
Captures the return value to assert on message, and knows subtypes match and there is a KClass overload.
Frames it as the multiplatform-safe alternative to try/catch/fail and JUnit assertThrows, with consistent semantics across targets.
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