Ok, so it's optional for generated tests... it mig...
# minutest
d
Ok, so it's optional for generated tests... it might be nice to clear that up in the docs 🙂. Also, does minutest support running
suspend
functions? I find tests with
runBlocking
all over the place can be hard to read...
d
Good point on willRun
I’ve avoided thinking about suspend, because every block would need a runBlocking version?
It’s on my list, but I’m not a (asynchronous) coroutines user, so hard.
If you can provide some use cases I’m up for the challenge
d
Really, only the root block that's being run needs runBlocking, and all the blocks under it can inherit it's coroutineContext... Also it would be nice to provide the CoroutineScope to those contexts to allow users to
launch
from that scope...
But then, I don't know the inners of Minutest enough...
Also, `inline fun`s don't need to suspend as long as they're running under the runBlocking.
d
When you say root block I guess you mean the rootContext? It takes a builder block, which may or may not be inline, I can’t remember offhand
There is a TestDescriptor passed into every block, you just don’t have to acknowledge its existence. It currently provides access to the name of the test, but we could smuggle a coroutine context through it too
d
If the root block runs before all contexts in every test and then the context and then the test, then the root block needs the runBlocking and the context and test need to inherit its CoroutineScope...
You mean that you already have
it
used by the
TestDescriptor
and
this
used by the fixture? Yeah, it's a nice solution to provide a
scope
property, anyways the scope is only used for `launch`ing or
async
calls, most of the time I call
suspend
functions that don't require one.
r
I don’t think you’d need coroutine-aware versions of the DSL methods. If the DSL methods accepted
suspend
functions it wouldn’t matter if the actual tests involved coroutines or not. I mean, theoretically there’s a small performance penalty but we’re talking about unit tests here, it’s not going to be noticeable.
d
I’m running to catch up with this discussion - I’ve not internalised any coroutine lore.
Am I right in thinking that if I make the DSL function types
suspend
all the way through, then at some point I will be responsible for providing the coroutine context - the problem being that there are potentially different contexts that could be used?
d
The context can always be changed with
withContext
and the likes, so the starting point is probably
runBlocking
. The solution I suggested is more of a hack I had used with Spek that made things livable... I agree with @robfletcher that having everything
suspend
would be a better solution, if possible.
d
I've taken a look at that approach, but ATM it's blocked (pun not intended) on a class
Test
that implements
TestLet
that is a typealias for the thing that is actually run, and would need to be
suspend
. But
Suspend function type is not allowed as supertypes
I can probably rejig things not to have the problem, but I'm going to need to understand the ramifications.
d
Where did you put
suspend
? AFAIK it should be in the typealias itself... where did you get the error?
d
Why
by f
? Maybe just implement the delgation yourself (just one invoke function, no?). Or you really need the inheritance?
d
Implementing the delegation doesn't help - the problem is that you can't implement a suspend function type.
I probably don't need the inheritance, it simplified things
but I could just fetch the property everywhere
d
I meant without the inheritance from the lambda...
An operator invoke might delegate to the lambda
Then you don't need to fetch the property, you could maybe have an interface for that...?
d
I think that would loose the suspend-ness that I have to chase through the code, unless that delegation was the point where I runBlocking
in which case I have to work out how to supply the a provided CoroutineContext (I think)
As I say, working on gut feel not experience here
d
The scope can be gotten by surrouding any suspend fun with
coroutineContext { }
once you have a base scope like runBlocking its running under. Like I said, the scope is only needed for using coroutine builders for concurency like launch or async, but to run regular suspend functions you wouldn't need a scope
At the same time coroutineScope {} allows cancelling on it without cancelling the main scope (if the main scope has a SupervisorJob)
d
OK, over my head now!
@dave08 what's the minimum coroutine support necessary to get you to stay at our little party?
d
Sounds daunting in the beginning, but the docs are pretty clear on structured concurrency, which is what you might need to understand so that the tests don't get stuck or all cancel etc... The minimum is a runBlocking around each test, and passing its scope to the test... a bit unefficient, but that could avoid the other problems...
Thanks for all your efforts 😉