I am trying to write some tests for this code:

private companion object {
    val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z")
}

fun getSomeValue(): String {
    val dateTime = ZonedDateTime.parse(config.getSomeDateTime(), formatter)
    return if (dateTime < ZonedDateTime.now()) {
        "A"
    } else {
        "B"
    }
}

Here is test which is not working:

@Test
fun testGetSomeValue() {
    mockkStatic(ZonedDateTime::class) {
        val mockZDT: ZonedDateTime = ZonedDateTime.of(2023, 12, 1, 12, 34, 56, 0, ZoneId.of("UTC"))
        every { ZonedDateTime.now() } returns mockZDT --> exception
        every { config.getSomeDateTime() } returns "2023-05-01 01:23:45 UTC"
        service.getSomeValue() shouldBe "A"
    }
}

Output from test is:

io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is mock

I have been looking for solution across internet and some places says it should work (i.e. OffsetDateTime issue.

On the other hand when I use Mockito solution with "mockStatic" from mockito-inline I have no issues. But this is a code I have inherited and need to make small change request, so I don't want to add additional dependency.

I am using:

  • mockk 1.13.5
1

There are 1 best solutions below

0
k314159 On

The following sample code is a complete, reproducible test that passes:

import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import org.junit.jupiter.api.Test
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter

class MyTest {
    interface Config {
        fun getSomeDateTime(): String
    }

    class Service(private val config: Config) {
        private companion object {
            val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z")
        }

        fun getSomeValue(): String {
            val dateTime = ZonedDateTime.parse(config.getSomeDateTime(), formatter)
            return if (dateTime < ZonedDateTime.now()) {
                "A"
            } else {
                "B"
            }
        }
    }

    val config = mockk<Config>()

    val service = Service(config)

    @Test
    fun testGetSomeValue() {
        mockkStatic(ZonedDateTime::class) {
            val mockZDT: ZonedDateTime = ZonedDateTime.of(2023, 12, 1, 12, 34, 56, 0, ZoneId.of("UTC"))
            every { ZonedDateTime.now() } returns mockZDT
            every { config.getSomeDateTime() } returns "2023-05-01 01:23:45 UTC"
            service.getSomeValue() shouldBe "A"
        }
    }
}

Versions: Mockk 1.13.8, Kotlin 1.9.21, JVM target 21.

To make it work on a recent JVM, you need to apply the workaround detailed in https://mockk.io/doc/md/jdk16-access-exceptions.html.