-
-
Notifications
You must be signed in to change notification settings - Fork 212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
expect..toThrow does not support suspend functions #363
Comments
Couldn’t you rewrite your example to suspend fun doSomething() {
throw IllegalStateException()
}
@Test
fun test() {
expect {
runBlocking {
doSomething()
}
}.toThrow<IllegalStateException>()
} and it would compile? I think that it would only be a disadvantage if you have a test runner that supports coroutines. Because in that case, you have to add Are there any test runners that support coroutines? |
Yes, that could work, but it creates pretty ugly nested test code. I guess I could create |
and share it with use afterwards 🙂
? (open for better names) |
@robstoll If we adopt this use case, I would prefer if we could make it so that you don’t need to use any differently named functions when using coroutines. |
I would prefer that as well but... I can imagine that the compiler won't be able to infer it correctly. Have to check though |
I came up with this: /**
* Variant of [expect] that wraps the code in [runBlocking], allowing
* for usage of suspending function inside the body.
*/
fun <T> expectBlocking(act: suspend () -> T): Expect<() -> T> {
return expect {
runBlocking {
act()
}
}
} simple extension but reduces the boilerplate. |
The following would be possible:
But the usage is not so nice, as you need a suspend lambda after
In case you prefer your |
Is there an use case this suspend method covers that expectBlocking doesn't? Otherwise I prefer expectBlocking since it's just one function call. Also, what is the difference between just calling |
What you could do with
Assuming we would add
|
In Kotlin, you can have overloads that only differ in the parameter being fun myExpect(block: () -> String): String = TODO()
fun myExpect(block: suspend () -> String): String = TODO() I propose we just add |
If this is true, I think the same name overload solution is the best. |
It's a nice idea but does not work out as Kotlin cannot be able to figure out which overload it should take if you write:
It will always be ambiguous unless you prefix it with We actually don't have an overload
Then Kotlin assumes you want to pass a regular lambda as I have pushed a prototype so that you can try out things yourself: |
Okay, multiple things to unwrap here:
Yes, that makes sense, because you can pass a normal lambda to a function taking a
I do not think so. If we add an fun <T> expect(subject: suspend CoroutineScope.() -> T): RootExpect<() -> T> =
ExpectBuilder.forSubject { runBlocking(block = subject) }
.withVerb(AssertionVerb.EXPECT)
.withoutOptions()
.build() (but only that) everything works fine, as far as I can see: expect("foo").toBe("bar") // resolved to the “normal” version
// normal lambda
expect { bar() }.toThrow<IllegalArgumentException>() // resolved to the suspend version, but that’s okay
// suspend lambda
expect { foo() }.toThrow<IllegalArgumentException>() // resolved to the suspend version
I ran resolving difficulties myself, but at least for me, the problem was something different. Kotlin does prefer the |
You're basically right, that's the way it should be but unfortunately it's not how the the current type inference system behaves. However, it seems it is fixed with the new type inference system (I guess you have not noticed the problem since you have activated the new type inference in IntelliJ, right?). Therefore we would need to wait until Kotlin 1.4 is out. Personally I would not use CoroutineScope but Also, we should think more about if it would not make sense to keep the type as |
must have been a glitch, it works now 🎉 |
Great! So we got ourselves a solution?
Function like You could make the argument that most users will not actually launch new coroutines but rather only call existing
Currently, I can not see any such use case. So if we do not find one, I would not propagate the As far as I can see, we can change the |
I think a basic idea at least. But the final implementation and test will show it, especially regarding other platforms than JVM. I don't know yet how to run a suspend fun on JS.
Can you add examples to test.kt please, I am not really familiar with kotlin coroutines yet.
that won't work as we need kotlinx.coroutines during runtime. We need an
That's true and we can still add it if someone requires it |
I have pushed a new commit to the branch, seems |
One way to go for JS: Kotlin/kotlinx.coroutines#885 |
I also only have basic knowledge. I can recommend Roman Elizarov’s “Structured Concurrency” on the topic of
I added a simple (and dump) example of something that relys on the receiver being
That’s great. To me, it seems like we can offer a good API to coroutine users without exposing coroutine functions to the users that do not need them. Neat.
Sounds promising! |
I think that makes a good point, I don't see why one would want to do async operations within
But... I am really not sure if Atrium should help out here. One could also write:
Even for more complicated things like:
But maybe I wander from the subject. One point we need to discuss is how we want to provide this new assertion verb. Personally I would be in favour of creating an additional
if we provide it in an additional module then I definitely don't see a problem of using CoroutineScope either |
I think the build just gave us the answer:
so we need another module as long as we support kotlin 1.2 |
Okay, so we go with the proposal but drop the |
another suggestion by @tenor-dev would be |
Platform (jvm, js, android): all
Extension (none, kotlin 1.3, jdk8): none
Code related feature
Following code that uses coroutines's suspend functions does not compile:
Problem stems from the fact that only
suspend
functions can call othersuspend
functions andexpect
is not a suspend function.Other assertion libraries (such as assertFails from kotlin-test) work around this problem by marking all assertion methods that accept lambda inline. Not sure how feasible is this for atrium.
Please react with 👍 if you would like to see this feature implemented in Atrium, the more upvotes the more likely I (@robstoll) will implement it myself -- feel free to sponsor me, that would be a motivation too.
You are of course welcome to work on this issue. Write
I'll work on it
as comment so that we can assign the task to you.The text was updated successfully, but these errors were encountered: