3

As title! I can't run any tests that are using MockK, as they end up throwing a StackOverflowError during initialisation.

As an example, here's one of my test classes:

@ExtendWith(MockKExtension::class)
class DBSequencesServicesTest {
    private lateinit var service: DBSequencesService

    @MockK
    private lateinit var sequencesRepo: DBSequencesRepo

    @BeforeTest
    fun initService() {
        service = DBSequencesServiceImpl(sequencesRepo)
    }

    @Test
    fun `should return value 0 if given a non-existent sequence`() {
        every { sequencesRepo.findById(any()) } returns Optional.empty()
        assertEquals(0, service.nextValue("test"))
    }

    @Test
    fun `should return next value if given an existing sequence`() {
        every { sequencesRepo.findById("test") } returns Optional.of(DBSequence("test", 1))
        every { sequencesRepo.save(any()) } returnsArgument 0
        assertEquals(1, service.nextValue("test"))
    }

    @Test
    fun `successive calls should return incrementing values`() {
        every { sequencesRepo.findById("test") } returnsMany listOf(
            Optional.of(DBSequence("test", 0)),
            Optional.of(DBSequence("test", 1)),
            Optional.of(DBSequence("test", 2))
        )
        every { sequencesRepo.save(any()) } returnsArgument 0

        for (i in 0L..2L) {
            assertEquals(i, service.nextValue("test"))
        }
    }
}

And this is the stack trace that results, cut off once the pattern becomes apparent:

Exception in thread "Test worker" java/lang/StackOverflowError
    at io/mockk/proxy/jvm/dispatcher/JvmMockKDispatcher.get (JvmMockKDispatcher.java:16)
    at java/lang/Object.hashCode (Object.java:119)
    at java/util/HashMap.hash (HashMap.java:339)
    at java/util/HashMap.get (HashMap.java:557)
    at sun/reflect/Reflection.filterMethods (Reflection.java:291)
    at java/lang/Class.getMethodHelper (Class.java:1265)
    at java/lang/Class.getMethod (Class.java:1191)
    at java/lang/Object.hashCode (Object.java:119)
    at java/util/HashMap.hash (HashMap.java:339)
    at java/util/HashMap.get (HashMap.java:557)
    at sun/reflect/Reflection.filterMethods (Reflection.java:291)
    at java/lang/Class.getMethodHelper (Class.java:1265)
    at java/lang/Class.getMethod (Class.java:1191)
    at java/lang/Object.hashCode (Object.java:119)
    at java/util/HashMap.hash (HashMap.java:339)
    at java/util/HashMap.get (HashMap.java:557)
    at sun/reflect/Reflection.filterMethods (Reflection.java:291)
    at java/lang/Class.getMethodHelper (Class.java:1265)
    at java/lang/Class.getMethod (Class.java:1191)
    at java/lang/Object.hashCode (Object.java:119)
    at java/util/HashMap.hash (HashMap.java:339)
    at java/util/HashMap.get (HashMap.java:557)
    ...

There's then a MessageIOException thrown:

org.gradle.internal.remote.internal.MessageIOException: Could not read message from '/127.0.0.1:52775'.
    at org.gradle.internal.remote.internal.inet.SocketConnection.receive(SocketConnection.java:94)
    at org.gradle.internal.remote.internal.hub.MessageHub$ConnectionReceive.run(MessageHub.java:270)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.lang.Thread.run(Thread.java:821)

So far as I can tell I've set up MockK correctly and am using it according to their guides:

dependencies {
    // Other dependencies go here...
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.4.10")
    testImplementation("io.mockk:mockk:1.10.2")
    testImplementation("com.ninja-squad:springmockk:2.0.3")
}

What's causing that exception, and how can I resolve it? Let me know if more context is needed.

EDIT: The same exception does not occur when CircleCI runs the tests using the image cimg/openjdk:8.0

EDIT 2: Added definitions of DBSequence and DBSequenceRepo

@Document(collection = "dbSequences")
data class DBSequence(
    @Id var name: String,
    var nextVal: Long
) {

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as DBSequence

        if (name != other.name) return false

        return true
    }

    override fun hashCode(): Int {
        return name.hashCode()
    }
}

interface DBSequencesRepo : MongoRepository<DBSequence, String>
Ian Knight
  • 2,356
  • 2
  • 18
  • 22

3 Answers3

6

There is an open issue in mockk related to the problem. The bug reproduces on a subset of JVM variations. I suppose you have one of such JVM installations locally. As a workaround, you may try to install a different JVM distribution locally. "AdoptOpenJDK: 1.8.0_222 hotspot" seems to be ok according to the link above.

sedovav
  • 1,986
  • 1
  • 17
  • 28
  • Looks like the issue is specifically with OpenJ9, which is what I was using! Installed a Hotspot JVM and tests now run. – Ian Knight Nov 04 '20 at 14:14
3

For me, I was getting the below error:

at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)`

and it turns out how mockK library was not working on certain version of Java 11 (particularly 11.0.10.j9-adpt)

if you are using sdkman, use the 11.0.10.hs-adpt version

| | 11.0.10.j9 | adpt | | 11.0.10.j9-adpt
| >>> | 11.0.10.hs | adpt | installed | 11.0.10.hs-adpt

mel3kings
  • 8,857
  • 3
  • 60
  • 68
1

We encountered a similar problem today on our local machines. We are trying MockK with vert.x and Kotlin for backend services.

Our development machines are MacOs with OpenJDK 11.0.9 and, for some strange reason, sometimes runs without a problem and sometimes stay alive until test timeout is thrown with a following message:

per (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/reflect/Reflection.filterMethods (java.base@9/Reflection.java:276)
    at java/lang/Class.getMethodHelper (java.base@9/Class.java:1457)
    at java/lang/Class.getMethod (java.base@9/Class.java:1361)
    at java/lang/Object.hashCode (java.base@9/Object.java:122)
    at java/util/HashMap.hash (java.base@9/HashMap.java:339)
    at java/util/HashMap.get (java.base@9/HashMap.java:552)
    at jdk/internal/

When we set JDK, in Idea project settins and Gradle, to 8.* there are the cases when one test passes and one fails with the same error as shown above.

I'm not expert of MockK library but I was very interested to compare it with mockito-kotlin. IMO library has some problems with reflection when used with recent versions of JDK.