doc / ch.tutteli.atrium.api.fluent.en_GB / toThrow

toThrow

inline fun <reified TExpected : Throwable> Expect<() -> Any?>.toThrow(): Expect<TExpected> (source)

Expects that the thrown Throwable is a TExpected (the same type or a sub-type).

Notice, that asserting a generic type is flawed. For instance toThrow<MyException<String>> would only check if the subject is a MyException without checking if the element type is actually String.

expect { throw IllegalStateException("abc") }
    .toThrow<IllegalStateException>() // subject is now of type IllegalStateException
    .messageToContain("abc")

fails {
    expect { throw IllegalStateException("abc") }
        .toThrow<IndexOutOfBoundsException>()
        .messageToContain("abc") // not shown in reporting as `toThrow<IndexOutOfBoundsException>()` already fails
}

Return
An Expect with the new type TExpected.

inline fun <reified TExpected : Throwable> Expect<() -> Any?>.toThrow(noinline assertionCreator: Expect<TExpected>.() -> Unit): Expect<TExpected> (source)

Expects that the thrown Throwable is a TExpected (the same type or a sub-type) and that it holds all assertions the given assertionCreator creates.

Notice, in contrast to other assertion functions which expect an assertionCreator, this function returns not Expect of the initial type, which was Throwable? but an Expect of the specified type TExpected. This has the side effect that a subsequent call has only assertion functions available which are suited for TExpected. Since Expect is invariant it especially means that an assertion function which was not written in a generic way will not be available. Fixing such a function is easy (in most cases), you need to transform it into a generic from. Following an example:

interface Person
class Student: Person
fun Expect<Person>.foo()        = "dummy"  // limited only to Person, not recommended
fun <T: Person> Expect<T>.bar() = "dummy"  // available to Person and all subtypes, the way to go
fun Expect<Student>.baz()       = "dummy"  // specific only for Student, ok since closed class

val p: Person = Student()
expect(p)               // subject of type Person
  .toBeA<Student> { ... } // subject now refined to Student
  .baz()                // available via Student
  .foo()                // not available to Student, only to Person, results in compilation error
  .bar()                // available via T : Person

Notice, that asserting a generic type is flawed. For instance toThrow<MyException<String>> would only check if the subject is a MyException without checking if the element type is actually String.

expect { throw IllegalStateException("abc") }
    .toThrow<IllegalStateException> { // subject inside this block is of type IllegalStateException
        messageToContain("abc")
    } // subject keeps type IllegalStateException also after the block

fails { // because wrong type expected (IndexOutOfBoundsException instead of IllegalStateException), but since we use a block...
    expect { throw IllegalStateException("abc") }
        .toThrow<IndexOutOfBoundsException> {
            messageToContain("abc") // ... reporting mentions that subject's message was expected `to contain: "abc"`
        }
}

fails {
    // because you forgot to define an expectation in the expectation group block
    // use `.toThrow()` if this is all you expect
    expect { throw IllegalStateException("abc") }
        .toThrow<IndexOutOfBoundsException> {}
}

Return
An Expect with the new type TExpected.