I have written a small library for async testing in Kotlin with JUnit, which is based on coroutines with runBlocking scope. I would like to have at least some kind of interop with Java. My coroutine knowledge is limited, but my idea was that if I let Kotlin create the scope and only bridge suspend function calls in Java class, passing the Continuation created by Kotlin method to method it might work. Currently I have something like this construct
class AsyncTestLibrary {
fun doSyncAction(){}
suspend fun doAsyncAction(){}
}
// JAVA compatibility wrapper
fun runTest(lib: AsyncTestLibrary, testBody: suspend (lib: AsyncTestLibrary) -> Unit) =
runBlocking {
testBody(lib)
}
And following usage in Java
@Test
public void test(){
runTest(testLibraryInstance, (lib, continuation) -> {
lib.doSyncAction();
lib.doAsyncAction(continuation);
return Unit.INSTANCE;
});
}
Unfortunately this approach does not seem to be working, getting some strange behavior and classCastExceptions like kotlin.coroutines.jvm.internal.CompletedContinuation cannot be cast to class kotlinx.coroutines.internal.DispatchedContinuation
Is there something fundamental about coroutines that means this will never work in general, or is there some interop library / approach I am missing?
If you're OK with converting the suspend functions into Futures for use in Java, then you could do it like this.
You would need a CoroutineScope for running the coroutines that back up the Futures, and you would need a wrapper function for each suspend function that you want to use in Java.
You need to use the kotlinx-coroutines-jdk8
library for this.
In this example, I believe I have used Kotlin and Java conventional naming for the functions. "Async" is never used in the names of suspend functions, but is typically used in function/method names that do not synchronously return a result. "Sync" is never used in function or method names.
class AsyncTestLibrary {
private val testScope = CoroutineScope(SupervisorJob()) + CoroutineName("TestScope")
fun doActionA(){}
suspend fun doActionB(): String { return "Test" }
suspend fun doActionC(input: String) { println(input) }
fun doActionBAsync() = testScope.future { doActionB() }
fun doActionCAsync(input: String) = testScope.future { doActionC(input) }
}
@Test
public void test(){
testLibraryInstance.doActionA();
testLibraryInstance.doActionBAsync()
.thenCompose(value -> testLibraryInstance.doActionBAsync(value));
}
I haven't personally done unit tests involving futures, so you'll have to look up how to wait for and assert results.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.