Is there any way to make a `spyk` intercept all ca...
# mockk
m
Is there any way to make a
spyk
intercept all calls to object AND make it relaxed at the same time?
m
Do you have a use case of what you would like to do?
m
I've got a class that wraps a generic type and am trying to write a spring test that sucks up all these "classes that need to be wrapped", wraps them and tests that the wrapping class does the right thing So I have something like...
Copy code
class Dispatcher(val wrapped: SomeClass<*>)
I essentially want to do (where toBeWrapped is injected via spring to the test)....
Copy code
@SpringBootTest
class DispatcherTests {
    @Autowired
    lateinit var toBeWrapped: List<ProviderModule<*, *>>

    @Test
    fun testGetDataDispatchedForEachProvider() {
        for (dispatcher in this.toBeWrapped.map { Dispatcher(it) }) {
            val moduleSpy = spyk(dispatcher.provider)
            every { moduleSpy.getData(any()) }
            dispatcher.getData(someData)
            verify { moduleSpy.getData(any()) }
        }
    }
}
of course the call to
getData
on
toBeWrapped
could be anything, which is represented as
Nothing
by the compiler, so am having trouble spying on it
(I know this scenario is a nightmare, but I am working with a protobuf
oneof
which makes it messy)
m
ow, that’s a nightmare indeed 😄
m
Essentially I am trying to verify that when a new one of the
toBeWrapped
classes are added, that a mapping is also added into the
Dispatcher
component
m
i think the best shot you can have at making it better would be to somewhat constrain the generic types, i.e. making them
* extends Something
rather than just
*
so that you can have your spied getData return something better than Nothing
does it make sense to you?
m
yeah unfortunately protobuf messages (hence classes generated) cannot inherit
m
oh, right 😞
m
Oh hang on - maybe they do actually, from a generic protobuf message class
oh great they do!
Copy code
public final class SomeCalss extends GeneratedMessageV3
Good outside the box thinking :D
m
nice 🙂
m
So this doesn't work as one of the generic parameters is contravariant so convert to Nothing anyway even with an extends. From the kotlin docs
For
Foo<in T>
, where
T
is a contravariant type parameter,
Foo<*>
is equivalent to
Foo<in Nothing>
. It means there is nothing you can write to
Foo<*>
in a safe way when
T
is unknown.
m
ouch
m
Ok I got success with dynamic calls mocking
Copy code
every { 
  dispatcherSpy invoke "dispatch" withArguments listOf(a, b) 
} returns response
m
uh, nice!
m
Ah the discovery continues, creating a relaxed mock from a class is also possible, and nicer.
Copy code
mockkClass(theClassInstance::class, relaxed = true)