1

I want to cover a case via test when exception is thrown. I've tried passing an incorrect input but still no luck.

In Kotest - can we explicitly throw exception when a function is called?

I couldn't find any documentation in Kotest Doc to cover this scenario:

Main.kt

parseEvent(input).forEach { event ->
    try {
        eventsProcessor(event)
    } catch (ex: Exception) {
        log.error { ex }
        batchItemFailures.add(SQSBatchResponse.BatchItemFailure(event.msgId))
    }
}

private fun eventsProcessor(event: Event<*>) {
    try {
        when (event.type) {
            "xyz" -> dailyprocess()
            else -> log.warn { "Unknown event type: ${event.type}" }
        }
    } catch (ex: Exception) {
        log.error { ex }
        throw ex
    }
}

Test.kt

describe("Event parsing") {

    context("when event is just a map") {
        val event = mapOf(
            "Records" to listOf(
                mapOf("body" to "jsonBody1")))

        it("parses and process event") {

            handler.handleRequest(event, createTestContext())
            val exception = shouldThrow<Exception> {
                dailyprocess(Instant.now())
            }

        }
    }
}
u-ways
  • 6,136
  • 5
  • 31
  • 47
rahul.cs
  • 45
  • 6

2 Answers2

3

Of course you can, here is a minimal example:

Let's say you have this implementation that throws an error (IllegalStateException) on failure:

fun aFailingImplementation(): Unit = 
  error("This is a failing implementation")

Then you can test this using the following:

@Test
fun `Assert exception is thrown`() {
    shouldThrow<IllegalStateException> {
        aFailingImplementation()
    }.apply {
        message shouldBe "This is a failing implementation"
        // stackTrace assertions can go here...
    }
}

You can read about testing exceptions here: https://kotest.io/docs/assertions/exceptions.html

u-ways
  • 6,136
  • 5
  • 31
  • 47
  • Nope , it doesn't cover the Exception Block. Control is not going to Exception Block. i.e during TestRun Control should go to batchItemFailures block and get recorded. But with above code or with Documentation , we can;t verify it – rahul.cs Feb 22 '23 at 06:04
  • 1
    Hmmm, then I am not sure I understand your question? Can you provide us with a minimal code example that we can use to replicate the problem? (The code example you have won't compile as it's missing pre-defined functions) – u-ways Feb 22 '23 at 09:11
0

It seems that you are quite confused about Kotest's shouldThrow function.

What it does: It asserts (i.e. checks) that the specified lambda block throws an exception.

What it doesn't: It does not make the specified lambda block throw an exception.

From your question and your comment on @u-ways' answer I take that you think it does the latter.

For that, you should either write your code in a way that you can stage it to throw an exception, by supplying it with input leading to an exception, or by using a class instead of static functions that you can prepare to be in a state that leads to an exception.

Or, you can use a mocking framework like mockk, and mock your function to throw an exception which can then be asserted by Kotest, like that:

it("parses and process event") {
    // tell mockk to mock static function dailyprocess
    mockkStatic(::dailyprocess)
    // tell mockk to throw an exception on any invocation of dailyprocess without argument
    every { dailyprocess() } throws Exception("expected test exception")

    // act + assert
    val exception = shouldThrow<Exception> {
        handler.handleRequest(event, createTestContext())
    }
}
Karsten Gabriel
  • 3,115
  • 6
  • 19