question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IllegalStateException: No lock present for object in Micronaut test with kotest

See original GitHub issue

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

I’m copying over an issue from Micronaut: https://github.com/micronaut-projects/micronaut-core/issues/3334 .

Expected Behavior

Mockk can be used within Micronaut test using kotest, with different mock behavior per test case.

Current Behavior

In the below example, an ExecutionException is thrown (stack trace below). Moving the every clause out of the test case makes the exception go away, but then the mock can only have one behavior per test file, which isn’t very usable.

Commentary from Micronaut devs is: “Seems to be some weird issue where the kotlin mocking library is introducing coroutines into the picture which introduces a concurrency issue where the lock is not visible from the couroutine thread. Why a mocking library needs to introduce concurrency and coroutines a Kotlin expert would need to explain.”

Failure Information (for bugs)

Steps to Reproduce

Run MyServiceTest in the project linked below for a repro case.

Context

  • MockK version: 1.10.1
  • Type of test: kotest unit test

Stack trace

No lock present for object: MyClient(#1)
java.lang.IllegalStateException: No lock present for object: MyClient(#1)
	at io.micronaut.runtime.context.scope.refresh.RefreshScope.getLock(RefreshScope.java:158)
	at io.micronaut.runtime.context.scope.refresh.RefreshInterceptor.intercept(RefreshInterceptor.java:46)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:69)
	at micronaut.issue.$MyServiceTest$MyClientMock0Definition$Intercepted.getSomeFoos(Unknown Source)
	at micronaut.issue.MyService.getFoos(MyService.kt:9)
	at micronaut.issue.MyServiceTest$1.invokeSuspend(MyServiceTest.kt:24)
	at micronaut.issue.MyServiceTest$1.invoke(MyServiceTest.kt)
	at io.kotlintest.runner.jvm.TestCaseExecutor$executeTest$supervisorJob$1$invokeSuspend$$inlined$map$lambda$1.invokeSuspend(TestCaseExecutor.kt:121)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

Minimal reproducible code (the gist of this issue)

https://github.com/theHacker/micronaut-issue-notlockpresent

Copying the test case from that link here:

package micronaut.issue

import io.kotlintest.specs.StringSpec
import io.micronaut.test.annotation.MicronautTest
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.kotlintest.MicronautKotlinTestExtension.getMock
import io.mockk.every
import io.mockk.mockk


@MicronautTest
class MyServiceTest(
        private val myClient: MyClient,
        private val myService: MyService
) : StringSpec() {

    @MockBean(MyClient::class)
    fun myClientMock(): MyClient = mockk()

    init {
        "MyService uses the MyClient" {
            every { getMock(myClient).getSomeFoos() } returns listOf(Foo(42, "Foo"))

            assert(myService.getFoos().size == 1)
        }
    }
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:4
  • Comments:5

github_iconTop GitHub Comments

3reactions
bjetalcommented, May 24, 2022

I realize this is rather old, but given the trouble it took me to track this down, I thought it was worth adding a comment:

One thing that can cause this exception is calling getMock for the first time inside the lambda for every or coEvery (or other setup functions). The reason is that this will trigger the bean being created and used as the key in Micronaut’s hash map for the refresh locks. Since you are in mock set up mode, the hashcode method (at least in some cases) returns 0 instead of the correct hashcode, which can cause the map entry to be stored in the wrong bucket of the hash map.

So, instead of:

    every { getMock(bean).m() } returns "value"

You need to do:

   var mockBean = getMock(bean)
   every { mockBean.m() } returns "value"
1reaction
ASAPHAANINGcommented, Apr 21, 2021

I figured it out:

@MicronautTest
class SomeTest(
val mockSomeHttpClient: SomeHttpClient
): FunSpec({
	test("some test") {
        every {
            getMock(mockSomeHttpClient).someFunctionOnTheClient(any())
        } returns HttpResponse.ok()
	}
}) {
    @MockBean(DefaultHttpClient::class)
    @Replaces(SomeHttpClient::class)
    fun mockSomeHttpClient(): SomeHttpClient = mockk(relaxed = true)
}

Replace SomeHttpClient and remember to use getMock in your test suite when accessing the injected variable

Read more comments on GitHub >

github_iconTop Results From Across the Web

Micronaut and KotlinTest | nerd.vision
java.lang.IllegalStateException: No lock present for object: AuditProducer(#67) at io.micronaut.runtime.context.scope.refresh.RefreshScope.
Read more >
No lock present for object in Micronaut test with kotest
Commentary from Micronaut devs is: "Seems to be some weird issue where the kotlin mocking library is introducing coroutines into the picture ...
Read more >
Micronaut Framework/questions - Gitter
... to inject that mocked bean into my test but I'm getting an error "java.lang.IllegalStateException: No lock present for object: " and I'm...
Read more >
Table of Contents - Micronaut Documentation
A new API EnvironmentEndpointFilter has been created to allow applications to customize which keys should have their values masked and which keys should...
Read more >
Micronaut Test
extensions.junit5.annotation.MicronautTest for JUnit 5. io.micronaut.test.extensions.kotest.annotation.MicronautTest for Kotest ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found