Hello :wave: Question: What would be the correct (...
# coroutines
t
Hello đź‘‹ Question: What would be the correct (or at least far from bad practice) approach for marrying a synchronous/sequential implementation with code that is not such? Case: An E2E test framework utilises ktor for communication with the app under test, where the calls are suspend functions. Tests by virtue require sequentiality for setup, execution and verification, so a
runBlocking
is used on the ktor using code. We don’t yet have a standardised approach for where to actually place the
runBlocking
so some tests wrap only the called methods (although other non async code is placed inside the block oftentimes), other have the entire test method as `fun
some test
= runBlocking {` . I was wondering if pushing the block lower into our logic (either into a facade or into the controllers as the first point of calling ktor) to avoid the aforementioned mishmash altogether would be a good idea. I’d be grateful for any pointers/opinions.
p
have you considered using TestCoroutineScheduler et al, as outlined in https://kt.academy/article/cc-testing?
t
I wasn’t exactly aware of it, no. But just to clarify - does the article pertain to testing coroutines themselves or utilising coroutines in tests?
p
it's basically about testing async, coroutines-based code in a way that becomes deterministic through enabling the test code to control the scheduling. i understood your question as wanting that kind of determinism, but perhaps you have a different use case?
t
Well, there might be some overlap between what you proposed and what I was refering to. If my question wasn’t 100% clear then I apologise, any miscommunication would stem from inexperience on my part. The tests in question are system/functional tests of an application, and any async/coroutine code is basically a tool to enable the tests, and are not in any way the scope of the tests. I was asking what would be the proper way of handling the async/coroutine utilising tooling inside of a synchronous/sequential focused implementation.
p
if i'm understanding you correctly, then my answer is "to make the test deterministic/feel like it's sequential, it's easiest to control the scheduling". Which is what the article is describing. An alternative is to use utilities like awaitility and do polling from the test code. that may be necessary or better for very high-level external code.
j
If the goal is to make real Ktor calls to real APIs, then you definitely don't want to use
kotlinx-coroutines-test
t
Yes, real ktor calls to real APIs. The crux is - if it’s fine to wrap the suspend functions
runBlocking
(as some coroutine scope is required) and if so, should it be done as early as possible (wrapping the call in a controller function) or in the last place, that being the actual test method
j
I'd usually do it in a wider scope (the test method level) to avoid the bloat of wrapping suspend calls all over the place