I have a function below that throws exception when failed to deserialize:
fun deserialize(payload: SdkBytes): List<Event>? {
return try {
val response = Json.decodeFromString<Response>(payload.asUtf8String())
return response.body
} catch (e: IllegalArgumentException) {
// if fails to deserialize
logger.error(e)
null
}
}
I have the following unit test to test when the exception is thrown:
fun testWhenMalformedJson() {
val body = "test body"
val bytes = SdkBytes.fromUtf8String(body)
expectCatching { deserialize(bytes) }
.isFailure()
.isA<IllegalArgumentException>()
}
When I try to run the test it fails with the following error:
▼ Expect that Success(null):
✗ is failure
returned null
Expected :null
Actual :null
I am unable to understand why my test is failing if actual and expected values are same.
First, it is recommended to use SerializationException
to catch any decoding-specific errors because IllegalArgumentException
is a generic exception that can also be thrown if the decoded input is not a valid instance of T
. See: kotlinx.serialization.json - decodeFromString
In regard to the test, it is failing for the correct reason. No exception is being thrown from your deserialize
method because it is being caught by the catch
block.
Instead, one way to test this logic would be asserting if null is being returned. (assuming response.body
returns a non-nullable type).
fun deserialize(payload: String): List<String>? {
return try {
return Json.decodeFromString<List<String>>(payload)
} catch (e: SerializationException) {
null // if fails to deserialize
}
}
@Test
fun `should return null when an exception is thrown`() {
val payload = "invalid"
val response = deserialize(payload)
assert(response == null)
}
@Test
fun `should return a list when deserialization is successful`() {
val payload = "[\"a\", \"b\", \"c\"]"
val response = deserialize(payload)
assert(response != null)
}
If you want to be more granular, you can static mockk the Json decoder to throw an exception using a library like Mockk to ensure null can only be returned by the catch block:
import io.mockk.every
import io.mockk.mockkObject
import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Test
@Test
fun `should return null when an exception is thrown`() {
mockkObject(Json.Default) {
every { Json.decodeFromString<List<String>>(any()) } throws SerializationException("invalid")
val response = deserialize("any string...")
assert(response == null)
}
}