Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.NoSuchMethodError: kotlinx.coroutines.SupervisorKt.SupervisorJob #1331

Closed
ps-snazhmudinov opened this issue Jul 10, 2019 · 17 comments

Comments

@ps-snazhmudinov
Copy link

Trying to use runBlockingTest for my unit tests, and getting the above-mentioned error.

Here are my code snippets:

@Test
    fun `test verify test call`() = runBlockingTest {
        registerViewModel.testCall()
        verify(repo).suspendedTestCall()
    }
fun testCall() {
        viewModelScope.launch(Dispatchers.IO) {
            repository.suspendedTestCall()
        }
    }
suspend fun suspendedTestCall() {
        kotlinx.coroutines.delay(2_000)
    }

Also getting the same error when trying to use TestCoroutineDispatcher.

@ps-snazhmudinov
Copy link
Author

Full log:

java.lang.NoSuchMethodError: kotlinx.coroutines.SupervisorKt.SupervisorJob$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;

	at kotlinx.coroutines.test.TestBuildersKt.checkArguments(TestBuilders.kt:94)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:46)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
	at at.rollingpin.register.RegisterViewModelTest.test verify test call(RegisterViewModelTest.kt:55)
	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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	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)

@elizarov
Copy link
Contributor

What's your environment? How do you get this problem?

@ps-snazhmudinov
Copy link
Author

ps-snazhmudinov commented Jul 15, 2019

What exactly do you mean by environment?

Also another thing - I made it work by injecting the dispatcher. Meaning it won't work without injecting the CoroutineDispatcher, correct me if I'm wrong?

@snazhmudinov
Copy link

Calls to withContext(Dispatchers.IO) or withContext(Dispatchers.Default) are common in coroutines based codebases. Both dispatchers are not designed to interact with TestCoroutineDispatcher.

Tests should provide a TestCoroutineDispatcher to replace these dispatchers if the withContext calls delay in the function under test. For example, a test that calls veryExpensiveOne should provide a TestCoroutineDispatcher using either dependency injection, a service locator, or a default parameter.

came across this on the github page

@45p3c7
Copy link

45p3c7 commented Jul 19, 2019

Calls to withContext(Dispatchers.IO) or withContext(Dispatchers.Default) are common in coroutines based codebases. Both dispatchers are not designed to interact with TestCoroutineDispatcher.
Tests should provide a TestCoroutineDispatcher to replace these dispatchers if the withContext calls delay in the function under test. For example, a test that calls veryExpensiveOne should provide a TestCoroutineDispatcher using either dependency injection, a service locator, or a default parameter.

came across this on the github page

Does it mean that whenever I need to use Dispaters.IO or Dispatcher.Default I have to provide it using dependency injection so that I can test it in the future? Or I incorrect get it?

@elizarov
Copy link
Contributor

It depends on your testing strategy.

@mnayef95
Copy link

Same issue here

java.lang.NoSuchMethodError: kotlinx.coroutines.SupervisorKt.SupervisorJob$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;

	at kotlinx.coroutines.test.TestBuildersKt.checkArguments(TestBuilders.kt:94)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:46)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
    @Test
    fun `test login behavior`() = runBlockingTest {
        userRepository.login(USERNAME, PASSWORD)
        coVerify {
            val user = remoteUserDao.login(USERNAME, PASSWORD)
            localUserDao.insert(user)
        }
    }
class UserRepositoryImpl(
    private val remoteUserDao: RemoteUserDao,
    private val localUserDao: LocalUserDao
) : UserRepository {

    override suspend fun login(username: String, password: String): User {
        val user = remoteUserDao.login(username, password)
        localUserDao.insert(user)
        return user
    }
}

Kotlin version: 1.3.41
kotlinx-coroutines-test version: 1.3.0-M2
Android studio version: 3.4.2
JUnit version: 4.12
Mockk version: 1.9.3

@elizarov
Copy link
Contributor

elizarov commented Aug 2, 2019

Can you, please, check that your kotlinx-coroutines-core and kotlinx-coroutines-test versions match.

@JakubMosakowski
Copy link

In my case, using

runBlockingTest {

}

every time throws error:

java.lang.NoSuchMethodError: kotlinx.coroutines.SupervisorKt.SupervisorJob$default(Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;

	at kotlinx.coroutines.test.TestBuildersKt.checkArguments(TestBuilders.kt:94)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:46)
	at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
	at com.jakmos.itemistevolved.useCase.InsertChecklistUseCaseTest.executeSuccess(InsertChecklistUseCaseTest.kt:37)
	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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	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)

on every version coroutines-test newer than:
kotlinx-coroutines-test version: 1.3.0-M1

My Kotlin plugin version: 1.3.41
Android studio version: 3.4.2

@elizarov
Copy link
Contributor

Does your version of kotlinx-coroutines-test matches with the version of kotlinx-coroutines-core?

@JakubMosakowski
Copy link

I thought kotlinx-coroutines-core is included to Kotlin itself. I haven't imported that package before, but after the error occurred I did, only to check if it's gonna fix the problem (it didn't), even when kotlinx-coroutines-core version was matching the kotlinx-coroutines-test.

@elizarov
Copy link
Contributor

@JakubMosakowski Is there any chance you can create and share a small project that would demonstrate the problem that you are experiencing?

@JakubMosakowski
Copy link

Sure, here it is: https://github.com/JakubMosakowski/test-project-coroutines
During preparing the test-project I found out that if I remove those 2 imports there is no error:

implementation "androidx.lifecycle:lifecycle-extensions:2.1.0-rc01"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-rc01"

@BenHenning
Copy link

FWIW I'm hitting the same issue. Backporting to org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.2 seems to resolve the issue for me until a root cause is known.

BenHenning added a commit to oppia/oppia-android that referenced this issue Aug 16, 2019
LiveData + kotlin coroutine system.

This introduces a custom LiveData to mediate between Kotlin coroutines
in a way that allows tests to actually ensure the coroutines resolve
quickly, and ensure lifecycle safety through standard LiveData
mechanisms.

However, this doesn't actually fix the underlying tests (which have been
changed in a number of ways in this commit in an effort to try and get
them to pass). The kotlinx coroutine deps were downgraded to work around
a NoSuchMethodError (see
Kotlin/kotlinx.coroutines#1331). After
introducing a runBlockingTest structure and updating the user app
histoyr controller to use the test context, the operations seem to work
correctly. However, one job is hanging which is causing the test to
still fail (it appears to be deadlocked--no known amount of time allows
it to resolve).

This new NotifiableAsyncLiveData also appears to break the production
behavior, as well. The LiveData result is no longer being observed by
the data binding transformation function, so it seems the coroutines
aren't being executed, aren't completing, or something is deadlocking
somewhere. Further investigation is needed.
@qwwdfsad
Copy link
Member

qwwdfsad commented Aug 20, 2019

The problem here is not in the library itself but in transitive dependencies.

How to verify you have this problem

In Android Studio or IntelliJ IDEA press Find symbol hotkey (cmd/ctrl+ N) and type kotlinx.coroutines.Job.
If you see more than two versions of the class (example), it's a dependency clash.

How to resolve the problem

You have multiple options here:

  1. Check whether dependencies that rely on coroutines can be updated and update them, if so
  2. Explicitly add kotlinx-coroutines-core (additionally to kotlinx-coroutines-android or kotlinx-coroutines-test or any other kx-coroutines dependency) with the desired version to your dependencies
  3. Resolve to the desired version of kotlinx.coroutines explicitly using custom Gradle resolution strategy

@JakubMosakowski thanks for the reproducer!

@JakubMosakowski
Copy link

Yep, It works.
Before adding custom Gradle resolution strategy:
image

After:
image

Thanks for your help!

JakubMosakowski added a commit to JakubMosakowski/test-project-coroutines that referenced this issue Aug 21, 2019
BenHenning added a commit to oppia/oppia-android that referenced this issue Aug 23, 2019
* Migrate ListenableFuture to a Kotlin coroutine, and split HomeActivity
into both an activity and a fragment.

* Introduce the domain and testsupport modules.

The domain module includes a user app history controller that provides
instances of a new AsyncResult interface that's meant to be a potential
bridge between Kotlin coroutines and LiveData. The exact design of how
this should work needs to be determined as part of #6.

This also includes a new testsupport module that's required due to
robolectric/robolectric#4736. This is supporting a
new test for the app history controller that leverages an AndroidX
activity scenario to test the live data.

Note that the test does not yet work since there's a race condition
between the LiveData's coroutines completing and the test continuing to
verify the state of the activity. This needs to be resolved, likely by
waiting for test visual elements to change based on the LiveData result.

Additional tests need to be added for other new components, and some
slight cleaning up may be necessary.

* Fix binary build: testsupport should only be depended on for tests, not
for production configurations.

* Further attempts to try and test the asynchronous behavior of the new
LiveData + kotlin coroutine system.

This introduces a custom LiveData to mediate between Kotlin coroutines
in a way that allows tests to actually ensure the coroutines resolve
quickly, and ensure lifecycle safety through standard LiveData
mechanisms.

However, this doesn't actually fix the underlying tests (which have been
changed in a number of ways in this commit in an effort to try and get
them to pass). The kotlinx coroutine deps were downgraded to work around
a NoSuchMethodError (see
Kotlin/kotlinx.coroutines#1331). After
introducing a runBlockingTest structure and updating the user app
histoyr controller to use the test context, the operations seem to work
correctly. However, one job is hanging which is causing the test to
still fail (it appears to be deadlocked--no known amount of time allows
it to resolve).

This new NotifiableAsyncLiveData also appears to break the production
behavior, as well. The LiveData result is no longer being observed by
the data binding transformation function, so it seems the coroutines
aren't being executed, aren't completing, or something is deadlocking
somewhere. Further investigation is needed.

* Fix the app not properly binding to the live data by ensuring the data
binder had the view model set properly. Fix resource binding issues in
Robolectric tests by ensuring binary resources are provided to
Robolectric. Fix the controller tests not working by introducing a
temporary, custom CoroutineLiveData that ensures no long-living jobs
continue running after the live data is completed.

* Clean up tests (we no longer need a testsupport module for this module
introduction).

* Add test for AsyncResult. Set code style for Groovy files & clean up all
build gradle files. Add missing newlines at end of various files.

* Reformat top-level build.gradle file, as well.

* Address review comments: replace name-based TODOs with issues.

* Address review comments: add EOF new lines.
@scottyab
Copy link

scottyab commented Jun 15, 2020

Just in case anyone else ends up here with this issue and finds that adding the resolutionStrategy not working in app/build.gradle, someone pointed me to adding it to the top level build.gradle in the allprojects block.

allprojects {
    repositories {
        ...
    }

    configurations.all {
        resolutionStrategy {
            force "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion"
            force "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"
            force "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutinesVersion"
        }
    }
} 

ext { kotlinCoroutinesVersion = '1.3.4' } 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants