https://kotlinlang.org logo
Title
d

dmcg

02/11/2020, 1:57 PM
@dave08 I think that this should be doable with the transforms abstraction built in, but TBH I’m scared of messing it up as I have never used coroutines concurrency in anger. If you can feed me some use-cases I’ll have a think.
d

dave08

02/11/2020, 2:02 PM
Just very simple testing of
suspend fun
calls and flows... the truth is, I'd suppose that surrounding each test with https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/run-blocking-test.html might be enough, but I don't know if that's what everybody might want in every case...
d

dmcg

02/12/2020, 9:09 AM
Yeah, that’s my problem too! As I see it testing coroutines is so much more than just waiting for them to finish that you’re always going to want access to the runBlockingTest scope explicitly
d

dave08

02/12/2020, 10:49 AM
But it could be provided as a
this
or
it
or are they both being used?
Also in Ktor, they used
this
(the receiver of the lambda) as an object providing a few things, including a
call
property...
d

dmcg

02/12/2020, 10:51 AM
We are using both,
this
for the fixture,
it
for a
TestDescriptor
. We could add things to the TestDescriptor, but I’m wary of making changes like that that I can’t back out.
Especially when I don’t really understand the use cases
d

dave08

02/12/2020, 10:53 AM
In Mockk, they have
every { }
and
coEvery { }
for non-coroutines, and coroutines mocking... you could technically have an extra experimental function like that too with a special
TestDescriptor
for it...
d

dmcg

02/12/2020, 10:54 AM
ATM we have
fun test(name: String, f: F.(testDescriptor: TestDescriptor) -> Unit): NodeBuilder<F> =
        test_(name) { testDescriptor ->
            this.apply {
                f(testDescriptor)
            }
        }
I could imagine saying
fun test(name: String, f: suspend F.(testDescriptor: TestDescriptor) -> Unit): NodeBuilder<F> =
        test_(name) { testDescriptor ->
            this.apply {
                testDescriptor.coroutineContext.runBlockingTest {
                    f(testDescriptor)
                }
            }
        }
which I think would be backwards compatible
But
anyone that writes a real coroutines test is going to end up pulling the
TestCoroutineScope
from the
testDescriptor
in order to call things like
advanceTimeBy
, in which case just adding your own
runBlockingTest
is a minor inconvenience?
As I say though, I don’t really know. Please do try to write some real-world coroutines tests and let me know where the pain is.
d

dave08

02/12/2020, 1:26 PM
The main pain is really the extra nesting everywhere... and to retrieve a scope could be just a question of an extension property/function
testScope
on
TestDescriptor
to avoid having to write all that ...
u

Uberto Barbini

02/13/2020, 9:28 AM
I think a CoroutineContext would work... but I'm struggling to see the use case so I won't try to implement it
d

dave08

02/13/2020, 11:34 AM
I'm struggling to see the use case
? Do you write tests for Coroutines? You don't mind having to nest an extra
runBlockingTest { }
within each step of the test?
I think all that nesting makes tests look much more messy... in JUnit it's just:
@Test fun testSomething() = runBlockingTest { ... }
so it's just one level, but in a DSL it makes things VERY hard to read.
I'm currently using KotlinTest which already implemented this, but I just don't really like the extra bloat of all those matchers in my namespace, and the fact that Fixtures aren't first class citizens...
d

dmcg

02/13/2020, 11:39 AM
I think you could add an extension function to TestContext to achieve this
u

Uberto Barbini

02/13/2020, 11:49 AM
my concurrent tests are quite complicated and they cannot be "just wrapped" I never had the need to test a single suspendable fun :)