mockk every {}.throws() Exception fails test

33k views Asked by At

I need to verify that a certain call is not made, when a previous method call throws an Exception.

    // GIVEN
    every { relaxedMock.eats() }.throws(NotHungryException())
    
    // WHEN
    sut.live()
    
    // THEN
    verify (exactly = 0) { relaxedMock2.sleeps() }

Problem with this code, it fails because of the Exception thrown and not because of the failed verification.

2

There are 2 answers

0
Patrick On BEST ANSWER

I understand that your WHEN block will always throw an exception. In that case you have multiple options from my point of view:

  1. Simple plain Kotlin. Wrap the WHEN block with a try-catch block, e.g. like this:
// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
    
// WHEN
var exceptionThrown: Boolean = false
try {
    sut.live()
} catch(exception: NotHungryException) {
    // Maybe put some assertions on the exception here.
    exceptionThrown = true
}
assertTrue(exceptionThrown)
    
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
  1. For a bit nicer code, you can use JUnit5 API's Assertions. assertThrows will expect an exception being thrown by a specific piece of code. It will fail the test, if no exception is thrown. Also it will return the thrown exception, for you to inspect it.
import org.junit.jupiter.api.Assertions

// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
    
// WHEN
val exception = Assertions.assertThrows(NotHungryException::class.java) { sut.live() }
    
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
  1. If you're using Kotest you can use the shouldThrow assertion. Which also allows you to retrieve the thrown exception and validate its type.
import io.kotest.assertions.throwables.shouldThrow

// GIVEN
every { relaxedMock.eats() }.throws(NotHungryException())
    
// WHEN
val exception = shouldThrow<NotHungryException> { sut.live() }
    
// THEN
verify (exactly = 0) { relaxedMock2.sleeps() }
0
Irfan Ul Haq On

I had similar issue and found that my method is not surrounded by try catch. This mean the method will always throw exception.

Test

The unit test to verify the result when the following method is called while stubbing it with predefine Exception

    @Test
fun returnSearchError() {

    every { searchService.search(query) }.throws(BadSearchException())

    val result = searchRepository.search(query)

    assertEquals(SearchStates.SearchError, result)

}

Faulty code

    fun search(query: String): SearchStates {
    val result = searchService.search(query)   // No try catch for the thrown exception 
    return try {
        SearchStates.MatchingResult(result)
    } catch (badSearchException: BadSearchException) {
        SearchStates.SearchError
    }
}

Refactored it to

fun search(query: String): SearchStates {
    return try {
        val result = searchService.search(query)
        SearchStates.MatchingResult(result)
    } catch (badSearchException: BadSearchException) {
        SearchStates.SearchError
    }
}