Laurent Thiebaud
10/24/2023, 12:31 PMmock<MyService> {
onBlocking {
with(any<MyContext>()) {
myMethod(vehicleId, deploymentName)
}
}.doReturn(success(lineExecutionStateResource))
}
with
context(MyContext)
suspend fun myMethod(...)
This works and this is standard.
As I write this piece of code at +100 places, I'd like to refactor it to extend the onBlocking
method to onBlockingWithMyContext
As of now, the onBlocking
method is defined as
fun <T : Any, R> KStubbing<T>.onBlocking(
m: suspend T.() -> R
): OngoingStubbing<R> {
return runBlocking { Mockito.`when`(mock.m()) }
}
so I'd like to indicate that the context of m
is T
and MyContext
. I found no way to define m
this way any idea?
As the end, the method body should be like
return runBlocking { with(any<MyContext>()) { Mockito.`when`(mock.m()) } }
AdamW
10/25/2023, 9:59 AMwith(any<SomeContextType>()) {
… }
? I guess you can reify a type parameter to be used with any
, and change the signature of m
so that it has a context receiver.Clement Petit
10/25/2023, 12:49 PMm
lambda, then the correct way of doing that is to add the context(MyContext)
part to the lambda type signature. On top of that, you need to pass the context as a regular parameter to the lambda, instead of using with
.
This should be something like this:
fun <T : Any, R> KStubbing<T>.onBlocking(
m: suspend context(MyContext) T.() -> R
): OngoingStubbing<R> {
val context = any<MyContext>()
return runBlocking {
Mockito.`when`(mock.m(context, this))
}
}
Maybe in the future, using the "parent" context when invoking a lambda with context receivers will be supported, but for now it isn't!Laurent Thiebaud
10/26/2023, 12:09 PMm: suspend context(MyContext) T.() -> R
with the context, for the compilator this is OK ✌️ with this
Mockito.`when`(mock.m(context, mock))
However at runtime I get
java.lang.ClassCastException: class MyMockClass cannot be cast to class MyContext
I can't figure out what I or kotlin is doing wrong here 🤔AdamW
10/26/2023, 5:11 PMwith
here, exactly as you did in the first example. Also, you can reify the context type and mark m
crossinline if you’re dealing with multiple context types, but I guess you only have MyContext
?Laurent Thiebaud
10/31/2023, 3:24 PMMyContext
, this is really strange it looks like a bug in the compiler 🤔
I tried every possible combination of context / context receiver but nothing works (either at compile time or run time)AdamW
10/31/2023, 3:25 PMwith
instead of passing the context as a parameter?Laurent Thiebaud
10/31/2023, 3:28 PMfun <T : Any, R> KStubbing<T>.onBlockingContext(
m: suspend context(MyContext) T.() -> R
): OngoingStubbing<R> {
val context = any<MyContext>()
return runBlocking {
with(context) {
Mockito.`when`(m(this@onBlockingContext.mock))
}
}
}
I still have the same runtime issue
java.lang.ClassCastException: class MyMockedClass cannot be cast to class MyContext (MyMockedClass and MyContext are in unnamed module of loader 'app')
(I cleaned the message to remove the real class names)