To test code in doStuff just test this function, d...
# coroutines
g
To test code in doStuff just test this function, do not test myMethod
👍 3
🤔 1
💯 2
a
doStuff()
is private Would you recommend to move to another class and have just a
manager
kind of class that will run coroutine in proper dispatcher and do nothing else?
g
I recommend to expose suspend functions as public API, instead of non-suspend functions that wrap them to launch or any other coroutine builder
a
So, basically, all coroutine-run methods should be public, to be testable without coroutines?
That really depends on the kind of class. For this particular one – I want it to manage
job
and handle cancelation if necessary, thus it’s not exposed as
suspend
g
I would think about in a little bit different way. Most of API that use coroutines should be suspend functions, such functions easy to test and user of this API can do anything what he want (wrap to GlobalScope.launch or run them in parallel in local scope)
Main problem of
myMethod
that you do not return Job
so cannot join and don’t know when function is finished
this is programming with side effect that even cannot be checked properly
and just use GlobalScope probably bad idea in this case
I don’t know exactly your case, but most probably there are some more clean ways to encapsulate lifecycle of
doStuff
than just GlobalScope.launch and a function that runs and forget
If you want example with Rx, it’s the same reasoning when you expose Observable/Single (correct way, same as suspend function) or hide it in a function that returns nothing, so it’s hard to test and you cannot control lifecycle or integrate to existing Rx code. This is exactly the same case with susepnd function (good) and global launch (bad)
Returning Job is little bit better, but still I would use suspend function (same way as in Rx better to return Observable/Single instead of just Disposable)
Would you recommend to move to another class and have just a
manager
kind of class that will run coroutine in proper dispatcher and do nothing else
Actually, this is one of possible solutions, but even in this case probably it can be somehow improved
a
So speaking in Android context, if I keep making all functions
suspend
then, essentially, only Activity/Fragment would be using dispatchers and would be running coroutines?
That would be exposing all jobs/subscription management to Activity/Fragment, that is bound to lifecycle and needs to handle rotation and other kinds of events
with Rx we were trying to avoid that, cutting subscription in UseCase or in Presenter directly
We could keep this in Presenter, then it would be this
manager
class
That is, essentially, what we did on backend – only Controllers start coroutines, and in some special cases that is
withContext
for services, that have to definitely run in background, like, 3rd party API calls
Just thinking how to properly structure that for Android too
g
If you want hide it from Activity, no problem, just hide it, use another top-level wrapper, it’s not neccessary should be Activity/Fragment I just mean that it’s hard to test such code, because you actually can only test side effects, not real functions. This imo looks more like integration testing than unit. And yeah, probably in this case make sense to provide different dispatcher and use it
I don’t think that Rx approach somehow different in terms of architecture
a
Well. With Rx, there is
subscribeOn
and
observeOn
, and once you get the description of those methods – it’s quite easy to see which thread code will be called on, and which thread will subscriber receive the data on. With coroutines it’s not that easy somehow.
g
But this is exactly the same. You have suspend function that doesn’t have any particular thread and call it from coroutine in particular thread