java.lang.ClassCastException: kotlin.Result cannot be cast to java.util.List
See original GitHub issuePrerequisites
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
Expected Behavior
I’m testing a class that has a suspend fun
and returns Result<List<..>>
. In a unit test I’m mocking this class and want to return a Result.success(...)
from that method. Expecting that my mock returns that value when called, but it crashes instead.
First I thought it’s a Kotlin bug and wanted to file an issue there, however, in production and when removing the mockk calls, the code works as expected, so I assume it’s instead a mockk bug.
This sample code snippet:
class ExampleUnitTest {
private val testClass = mockk<TestClass>()
@Test
fun `test bug`() = runBlockingTest {
coEvery { testClass.execute() } returns Result.success(listOf("1"))
testClass.execute()
.fold(
onSuccess = {
println(it)
},
onFailure = {
println("fail")
}
)
}
}
class TestClass {
suspend fun execute(): Result<List<String>> {
return suspendCoroutine {
it.resume(Result.success(listOf("")))
}
}
}
crashes with
java.lang.ClassCastException: kotlin.Result cannot be cast to java.util.List
at de.syex.resultbug.ExampleUnitTest$test bug$1.invokeSuspend(ExampleUnitTest.kt:24)
at de.syex.resultbug.ExampleUnitTest$test bug$1.invoke(ExampleUnitTest.kt)
at kotlinx.coroutines.test.TestBuildersKt$runBlockingTest$deferred$1.invokeSuspend(TestBuilders.kt:50)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.test.TestCoroutineDispatcher.dispatch(TestCoroutineDispatcher.kt:50)
...
The offending line 24 is the fold()
. I found this issue while testing some code that actually runs fine. Instantiating TestClass
instead
private val testClass = TestClass()
lets the test pass as expected.
- MockK version: 1.10.0
- Kotlin version: 1.4.0
- Coroutine version: 1.3.9
- JDK version: 1.8
- JUnit version: 4.12 & 5.6.2
- Gradle version: 6.1.1 & 6.5.1
- Type of test: unit test
Issue Analytics
- State:
- Created 3 years ago
- Reactions:17
- Comments:17 (1 by maintainers)
Top Results From Across the Web
ClassCastException: foo.Bar cannot be cast to kotlin.Result
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to kotlin.Result at org.example.App$onCreate$1.invokeSuspend( App.kt:65 ) ...
Read more >ClassCastException: <type> cannot be cast to kotlin.Result
One of the surprising features in Kotlin 1.3 release was built in functional Either monad implementation called Result.
Read more >Result nested twice when collecting a Flow in Kotlin 1.5 (kotlin ...
Show activity on this post. I have The same issue I downgraded the kotlin version from 1.5. 10 to 1.4. 32 and the...
Read more >How to fix java.lang.classcastexception cannot be cast to in Java
As name suggests ClassCastException in Java comes when we try to type cast an object and object is not of the type we...
Read more >kotlin.Result cannot be cast to java.util.List - Bountysource
java.lang.ClassCastException: kotlin.Result cannot be cast to java.util.List at de.syex.resultbug.ExampleUnitTest$test bug$1.invokeSuspend( ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I have reported it straight to the Kotlin team: https://youtrack.jetbrains.com/issue/KT-46477#focus=Comments-27-4952485.0-0 Because it is a language-level bug.
I’ve seen the implementation that has been done in Mockito to handle this.
It seems like we can replicate it in mockk, it’s basically about trying to unbox the underlying value contained in the Result class if possible and returning it in the answerer.
However, it’s only feasible from Kotlin 1.5.0 onwards, because it requires the @JvmInline annotation to be available and set on the Result class (or any other inline class, for that matter).
Given the fact that 1.5.0 was released very recently and using Result as a return type is not possible by default but it requires the
-Xallow-result-return-type
kotlin option to be set, this doesn’t look to me like a high priority issue right now.Reopening it for now and leaving it here in case anyone wants to submit a PR.