Marcelo Hernandez
05/18/2019, 8:55 PMrunBlockingTest
, TestCoroutineDispatcher
, TestCoroutineScope
, etc. They look promising, however I haven't been able to figure out a way to stub a dependency's suspend
function using mockito-kotlin
such that it suspends indefinitely. The goal is to test scenarios within my Android ViewModel
where onCleared()
is called before a suspend
function returns a result. Basically something like:
private fun givenStatusNeverReceived() = runBlocking {
// loadStatus() is a suspend function
given(repository.loadStatus()).willAnswer {
// suspend indefinitely
}
}
efemoney
05/19/2019, 7:39 PMFlow
is cancelled/disposed. Something like ObservableEmitter.setCancellable { ... }
in the rx world.
I want to use Flow
to model an add/remove listener so that a listener is attached when the flow is “subscribed” to and detached when the subscription is “disposed”. Forgive the rx lingo, pretty new to Flow
so I will also appreciate reading material that can tie or at least differenciate between my RxJava knowlege and Flow
ribesg
05/20/2019, 10:29 AMkotlinx-coroutines-test
in my test dependencies.
java.lang.NullPointerException
at kotlinx.coroutines.CoroutineContextKt.newCoroutineContext(CoroutineContext.kt:57)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:50)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
kupris
05/20/2019, 12:28 PMilya-gh
05/20/2019, 12:49 PMdelay
in the following code:
class A(val coroutineContext: CoroutineContext = EmptyCoroutineContext) {
fun work(): String {
val result = runBlocking(coroutineContext) {
delay(3000)
return "some_result"
}
return result
}
}
@Test
fun `tests work`() {
val result = A().work()
assertEquals("some_result", result)
}
If a pass TestCoroutineContext()
to runBlocking the delay
is ignored as expected. However, It’s deprecated in favor of TestCoroutineScope.
TestCoroutineScope. However If I pass TestCoroutineScope the test never finishes:
@Test
fun `tests work`() {
val result = A(TestCoroutineScope(TestCoroutineDispatcher()).coroutineContext).work()
// never reaches here
assertEquals("some_result", result)
}
What I am missing?Alexjok
05/20/2019, 1:11 PMWilson Castiblanco
05/20/2019, 5:50 PMOleh Havrysh
05/21/2019, 9:39 AMsuspendCoroutine
that doesn’t require passing result value?Marko Mitic
05/21/2019, 11:28 AMselect
. Is that fine? Are there any channel constructs that could help?louiscad
05/21/2019, 1:51 PMFlow
very well designed, kudos to the people involved.
I like how it reuses the continuation of the consumer and how exceptions and cancellation are propagated.
Is it bad to use them in production under their preview status? :yes: or 🇳🇴sam
05/22/2019, 7:06 PMBob Glamm
05/22/2019, 7:18 PMlaunch
require a corresponding join
or will the coroutine resources created with launch
be automatically reclaimed on coroutine completion?tseisel
05/22/2019, 9:03 PMFlow
have a corresponding select
clause, and if it doesn't, is it planned ?Antanas A.
05/24/2019, 8:08 AMAntanas A.
05/24/2019, 12:45 PMgotoOla
05/24/2019, 3:10 PMMatej Drobnič
05/25/2019, 7:57 AMMainDispatcher.immediate
over just regular MainDispatcher
?Winowiczlukasz
05/26/2019, 6:50 PMDico
05/27/2019, 3:43 AMdelay
suspend forever, if I pass it a value around 500-1500 MS?
I have some code that is looping with an interval which works perfectly in one environment but not in another - where it's used as a plugin in some other software.
The dispatcher used is a single thread dispatcher created using Executors.newSingleThreadDispatcher(threadFactory).asCoroutineDispatcher()
The behavior I'm seeing is that it never resumes the coroutine.Tuan Kiet
05/28/2019, 2:08 AMSteven
05/28/2019, 2:43 PMMark
05/29/2019, 6:31 AMsuspend fun File.trackLength(fileLengthCallback: (Long) -> Unit, refreshInterval: Long = 100L, block: suspend () -> Unit) {
val deferred = GlobalScope.async {
block()
}
while (deferred.isActive) {
fileLengthCallback(length())
delay(refreshInterval)
}
fileLengthCallback(length())
}
Jacques Smuts
05/29/2019, 9:12 AMefemoney
05/29/2019, 10:24 AMcoroutineScope
and launch
? (Its not super clear from the docs)Mark
05/29/2019, 12:11 PMsuspend fun myFun() {
repeat(100) {
someSuspendingFunSpecifyingIODispatcher()
someQuickNonSuspendingFun()
}
}
At the top-level of myFun() is it better to have withContext(Dispatchers.IO), coroutineScope {} or leave it as it is?Dan Johansson
05/29/2019, 3:54 PMasync
(and .await
in my test) it fails as expected but I want to use launch
(actual function is in my Android ViewModel) and I am kinda lost.
A workaround is to check whether the job isCancelled
, which works but is a bit clunky (I guess it's possible to create some test rule..). I've read the docs but haven't come up with anything. Maybe I'm going about this the wrong way and there's a better approach? Any pointer or direction is very much appreciated.
// in ViewModel
val job = Job()
val viewModelScope = CoroutineScope(Dispatchers.Main + job)
fun someFunction() = viewModelScope.launch {
throw IllegalStateException("reasons")
}
...
@Test
fun `should fail`() = runBlocking {
// prints error but the test passes
someFunction().join()
}
@Test
fun `successfully failing workaround`() = runBlocking {
// this feels wrong
val job = someFunction()
someFunction.join()
assertFalse(job.isCancelled)
}
rook
05/30/2019, 7:43 PMsuspend fun waitForUpdates(): ReceiveChannel<Update> = produce {
onUpdateHook { update ->
send(update)
}
}
fun startWaitingForUpdates() {
launch {
waitForUpdates().onReceive { update ->
doUpdate(update)
}
}
}
coder82
05/31/2019, 8:07 AMcoder82
05/31/2019, 9:06 AMTuan Kiet
06/02/2019, 8:47 AMwithContext
to get this
as a coroutine context?Tuan Kiet
06/02/2019, 8:47 AMwithContext
to get this
as a coroutine context?tseisel
06/02/2019, 8:53 AMCoroutineScope
, not a CoroutineContext
.
The best way to obtain the CoroutineScope of a coroutine is to pass it as argument to the function that needs it.fun CoroutineScope.launchMyJob(...)
Functions defined like this does not suspend until the job is completed, as opposed to suspend fun
.simon.vergauwen
06/02/2019, 8:54 AMcoroutineContext
as a property available within any suspend
function or lambda.Tuan Kiet
06/02/2019, 9:00 AMsuspendCoroutineUninterceptedOrReturn
or withContext
simon.vergauwen
06/02/2019, 9:02 AMsuspendCoroutineOrReturn
is what you're looking for. It's rather low level.Tuan Kiet
06/02/2019, 9:25 AMgildor
06/02/2019, 9:49 AMTuan Kiet
06/02/2019, 9:56 AMcoroutineScope
pretty sure within a suspend function coroutineScope is a functionpublic suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R
gildor
06/02/2019, 9:57 AMTuan Kiet
06/02/2019, 9:57 AMcoroutineScope{}
or withContext{}
?gildor
06/02/2019, 9:59 AMTuan Kiet
06/02/2019, 10:01 AMgildor
06/02/2019, 10:02 AMTuan Kiet
06/02/2019, 10:05 AMsuspend fun sdfsdf(): Job {
return coroutineScope {
launch {
}
}
}
gildor
06/02/2019, 10:05 AMTuan Kiet
06/02/2019, 10:06 AMgildor
06/02/2019, 10:06 AMTuan Kiet
06/02/2019, 10:07 AMgildor
06/02/2019, 10:07 AMTuan Kiet
06/02/2019, 10:08 AMgildor
06/02/2019, 10:08 AMTuan Kiet
06/02/2019, 10:08 AMgildor
06/02/2019, 10:09 AMTuan Kiet
06/02/2019, 10:12 AMoverride suspend fun doWork(): Result = coroutineScope {
workJob = launch {
doActualWork()
}
workJob?.invokeOnCompletion {
if (it != null) {
showStoppedNotification()
}
}
Result.success()
}
private suspend fun doActualWork() {
// stuff
}
gildor
06/02/2019, 10:14 AMsuspend fun sdfsdf() {}
// On call site
val job = launch { sdfsdf() }
//Launch invocation in background and also may be cancelled
job.cancel()
Tuan Kiet
06/02/2019, 10:15 AMgildor
06/02/2019, 10:16 AMTuan Kiet
06/02/2019, 10:17 AMgildor
06/02/2019, 10:17 AMTuan Kiet
06/02/2019, 10:17 AMgildor
06/02/2019, 10:19 AMTuan Kiet
06/02/2019, 10:21 AMgildor
06/02/2019, 10:21 AMoverride suspend fun doWork(): Result {
try {
doActualWork()
} catch (e: CancellationException) {
// You can handle cancellation separately, if you want
} catch (e: Exception) {
showStoppedNotification()
//Should we return Result.fail()?
}
return Result.success()
}
private suspend fun doActualWork() {
// stuff
}
Tuan Kiet
06/02/2019, 10:23 AMdoWork
is called by that framework and canceled by the framework too, do we need doActualWork at all?gildor
06/02/2019, 10:24 AM//stuff
somewhere, isn’t it? I mean nothing prevents you from inline it in doWork, like with any other function, I’m not sure what is your concern in this caseTuan Kiet
06/02/2019, 10:25 AMgildor
06/02/2019, 10:29 AMTuan Kiet
06/02/2019, 10:35 AMgildor
06/02/2019, 10:38 AMDico
06/02/2019, 11:22 AMgildor
06/02/2019, 12:12 PM