Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 563 Vote(s) - 3.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
In kotlin, how do I mock a suspend function that wraps a callback?

#1
Let's say there's an interface with a callback:

interface SomeInterface {
fun doSomething(arg: String, callback: (Exception?, Long) -> Unit)
}

which I extend into a suspend function like this:

suspend fun SomeInterface.doSomething(arg: String): Long = suspendCoroutine { cont ->
this.doSomething(arg) { err, result ->
if (err == null) {
cont.resume(result)
} else {
cont.resumeWithException(err)
}
}
}

I'd like to mock this in tests, but am failing.
Ideally I'd like to use something like this:

@Test
fun checkService() {
runBlocking {
val myService = mock<SomeInterface>()
whenever(myService.doSomething(anyString())).thenReturn(1234L)
val result = myService.doSomething("")
assertEquals(result, 1234L)
}
}

The above syntax fails with a mockito exception because it's expecting a matcher for the callback.

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:

How can I mock a suspend function like that?
If a similar syntax is not possible how can I have the mock call back with the desired arguments such that the suspend variant that is used throughout my code returns the desired result during tests?


**Update**:
It seems it's not possible when it's an extension function. Based on [Marko Topolnik][1]'s comment, I gather it's because an extension is simply a static function which is out of mockito's capability.

When the suspend function is a member function, then it works as expected, with my original syntax.

Here is a gist with some demo code:



[1]:

[To see links please register here]

Reply

#2
I suggest using [MockK](

[To see links please register here]

) for your tests, which is more coroutine-friendly.

To mock a coroutine, you can use `coEvery` and `returns` like below:

val interf = mockk<SomeInterface>()
coEvery { a.doSomething(any()) } returns Outcome.OK
Reply

#3
When you need to

> on .... do return ..

and method is suspended, with **mockito** you can use this:

- use this lib [mockito-kotlin][1]
- Mock your object, lets name it myObject (myObject has suspend method named isFoo)

then:

myObject.stub {
onBlocking { isFoo() }.doReturn(true)
}


[1]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through