kotlinx.coroutines: [question] Is this "IllegalStateException: This job has not completed yet" while using runBlockingTest normal?

Why when executing the following test:

@Test
fun foo() = runBlockingTest {
  bar()
}

suspend fun bar() {
  println(1)
  withContext(Dispatchers.IO) {
	 println(2)
  }
  println(3)
}

The output is:

1
2
3

java.lang.IllegalStateException: This job has not completed yet

	at kotlinx.coroutines.JobSupport.getCompletionExceptionOrNull(JobSupport.kt:1114)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
	at com.foopkg.MyTests.foo(MyTests.kt:11)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:628)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:117)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:184)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:180)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:127)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1251)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.util.ArrayList.forEach(ArrayList.java:1251)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Is it related to #1204 ?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 18
  • Comments: 22 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I replaced runBlockingTest on runBlocking and it helped.

Thanks for the minimal repro!

In the current version there’s an issue that causes runBlockingTest to throw this exception incorrectly when there are multiple threads. This is the same issue reported in https://github.com/Kotlin/kotlinx.coroutines/issues/1204

Patch https://github.com/Kotlin/kotlinx.coroutines/pull/1206 will change this to pass as expected.

In my case, I had to do this while using runBlockingTest:

val job = launch {
            val tasksLists = tasksLisDao.tasksLists()

            assertEquals(tasksLists.toList(), testValues)
        }

        job.cancel()

I am not sure if it is the right way but the test passed thou.

The one annoying thing about runBlocking is that JUnit tests don’t run unless they return Unit, but it’s hard to remember to always type runBlocking<Unit> or fun testFoo(): Unit = runBlocking`.

We use this just to get around that:

fun testBlocking(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() }

Still continuing. I am using a custom CoroutinesTestRule but still getting this issue. Any workaround except using runBlocking?

I replaced runBlockingTest on runBlocking and it helped.

runBlocking works for me too

private val testDispatcher = TestCoroutineDispatcher()

@Before
fun setup() {
	Dispatchers.setMain(testDispatcher)
}

@After
fun cleanUp() {
	Dispatchers.resetMain()
	testDispatcher.cleanupTestCoroutines()
}

@Test
fun testCoroutines1() = runBlocking {
	withContext(Dispatchers.Main) {
		Assert.assertEquals(job1().await() and job2().await(), false)
	}
}

@Test
fun testCoroutines2() = runBlocking {
	withContext(Dispatchers.Main) {
		Assert.assertEquals(job1().await() or job2().await(), true)
	}
}

suspend fun job1() = GlobalScope.async(Dispatchers.Default) {
	delay(1000)
	true
}

suspend fun job2() = GlobalScope.async(Dispatchers.Default) {
	delay(500)
	false
}

@qwwdfsad Is there any place where we can track the progress? I can see the https://github.com/Kotlin/kotlinx.coroutines/pull/1206 was closed, but I couldn’t find any further updates.

My problem was I was using Robolectric to test a class that used Google’s LocationProvider for Location and using a suspend function locationManager.getLocation() which caused the exception with runBlockingTest .

The only solution was this to use GlobalScope.launch { } to test it. I didn’t even need the coroutine test rules or anything:

class LocationManager(private val fusedLocationProviderClient: FusedLocationProviderClient) {

    @SuppressLint("MissingPermission")
    suspend fun getLocation(): LocationCoordinates? =
        fusedLocationProviderClient.lastLocation.await().toLocationCoordinates()

    data class LocationCoordinates(val long: Double, val lat: Double)

    private fun Location.toLocationCoordinates(): LocationCoordinates = LocationCoordinates(this.longitude, this.latitude)
}
@RunWith(AndroidJUnit4::class)
@Config(sdk = [Build.VERSION_CODES.P])
class LocationManagerTest {
    private lateinit var locationManager: LocationManager

    @Before
    fun setUp() {
        val client = LocationServices.getFusedLocationProviderClient(getApplicationContext() as Context)
        client.setMockMode(true)
        val location = Location("lol")
        location.longitude = 11.0
        location.latitude = 12.0
        client.setMockLocation(location)
        locationManager = LocationManager(client)
    }

    @Test
    fun `test location coordinates`() {
        GlobalScope.launch {
            val location = locationManager.getLocation()
            assertEquals(location!!.long, 11.0)
            assertEquals(location.lat, 12.0)
        }
    }
}

Initially I was running the test like this, with coroutine test dispatchers and instant task executor rules and whatnot, and got the Job not completed exception:

    @Test
    fun `test location coordinates`() = runBlockingTest {
            val location = locationManager.getLocation()
            assertEquals(location!!.long, 11.0)
            assertEquals(location.lat, 12.0)
    }

this also caused an exception:

    @Test
    fun `test location coordinates`() = testContextProvider.testCoroutineDispatcher.runBlockingTest {
          val location = locationManager.getLocation()
            assertEquals(location!!.long, 11.0)
            assertEquals(location.lat, 12.0)
    }

Maybe this will help someone.

Hi,

i’m facing same issue as described above executing my room database unit tests.

Has there been found out any fix for that ?

In my case, I had to do this while using runBlockingTest:

val job = launch {
            val tasksLists = tasksLisDao.tasksLists()

            assertEquals(tasksLists.toList(), testValues)
        }

        job.cancel()

I am not sure if it is the right way but the test passed thou.

using this if assert value is not equal then also the test will get pass