What is the difference between verify(exactly = 0) and wasNot Called in Mockk? - kotlin

What is the difference between using verify(exactly = 0) and using wasNot called assertions of MockK when testing Kotlin?
I have an example where the former passes the test but the latter yields:
java.lang.AssertionError: Verification failed: call 1 of 1: KLogger(#1).error(any())) was not called.
Code sample:
private val logger = mockk<KLogger>()
...
#Test
fun `logMessage should log message with info log level`() {
...
every { logger.info(logMessage) } just runs
...
verify(exactly = 1) { logger.info(logMessage) }
verify { logger.error(any<String>()) wasNot Called }
}

For checking if a function on the mock was called or not, verify must be used based on this comment:
Construction like verify { mock wasNot Called } is used not for
function but for whole mock
This works correctly:
verify(exactly = 0) { logger.error(any<String>()) }

Related

Why is mockk executing a method when I'm checking for not invoked scenario?

I have a scenario like
fun someMethod() {
try {
val response = callApi.method()
val output = processResponse(response)
} catch (throwable: Throwable) {
}
}
Now I'm testing for the scenario when callApi.method() throws an exception and the method processResponse() is not invoked. It is working as expected but mockk is failing
verify(exactly = 0) { processResponse(any()) }
verify { processResponse(any()) wasNot Called }
with this error:
java.lang.NullPointerException: Parameter specified as non-null is null
My question is that why mockk is trying to execute the processResponse() method with a null response from any() when I'm just verifying that the method is not invoked? Are there any other ways to avoid this error? Thanks

Mocking internal function call in Kotlin

I am a complete beginner in terms of Kotlin and I am finding some issues while trying to test out a Ktor based application.
I have a file in my endpoints package localized at org.example.endpoints.hello
this file contains a fun Application.hello that implements an endpoint for my application.
This endpoint acts as a wrapper for another API, so inside that same file I have a
fun callOtherAPI(): ResponseContainer {
// networking stuff
return ResponseContainer(message: "some stuff")
}
This function gets called inside the Application's function routing implementation as such:
routing {
get("/hello") {
call.respond(callOtherAPI())
}
}
Now to the issue:
My test currently looks like this:
#Test
fun testHello() = testApplication {
application {
hello()
}
mockkStatic(::callOtherAPI)
every { callOtherAPI() } returns ResponseContainer("hello")
print(callOtherAPI()) // This actually returns the mocked response, which is what I want
client.get("/hello").apply {
val expected = ResponseContainer("hello")
val response = jacksonObjectMapper().readValue<ResponseContainer>(bodyAsText())
assertEquals(HttpStatusCode.OK, status)
assertEquals(expected.message, response.message) // This assert fails because the internal call to callOtherAPI() is not being mocked.
}
}
So the problem that I am facing is that while the mocked function is being mocked within the context of the test, it is not being mocked when called internally by the routing implementation.
Can someone point me to good documentation to figure this out, I've been at it for the past two hours to no avail :/
Thanks!
You can declare a parameter for the callOtherAPI function in the hello method. For the production and testing environment you will pass different functions in this case. Here is your code rewritten:
#Test
fun testHello() = testApplication {
application {
// hello(::callOtherAPI) this call will be for the production environment
hello { ResponseContainer("hello") }
}
client.get("/hello").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("{\"message\":\"hello\"}", bodyAsText())
}
}
data class ResponseContainer(val message: String)
fun Application.hello(callOtherAPI: () -> ResponseContainer) {
install(ContentNegotiation) {
jackson()
}
routing {
get("/hello") {
call.respond(callOtherAPI())
}
}
}
fun callOtherAPI(): ResponseContainer {
// networking stuff
return ResponseContainer("some stuff")
}

Mockk: Execute callback code in real object calling a mockk service

I try to achieve something similar to this: How to call a lambda callback with mockk
I pass a mocked service to my real object. How can I get the myService.get callback called? This code gets never called and my test stops at this request.
Here is some sample code:
class MyObject(private val myService: MyService){
fun getSomeStuff() {
myService.get(object: MyService.Callback<MyServiceResponse>{
override fun onResponse(response: MyServiceResponse?) {
// check response and do some stuff
// I want to continue my tests here, but this gets never called
}
})
}
How can I create a test that continues inside the callback?
Here is what I trie in my test:
#Test
fun `get some stuff - success`() {
val myService = mockk<MyService>() {
every { get(any()) } answers {
firstArg<() -> MyService.Callback<MyServiceResponse>>().invoke()
}
}
val myObject = MyObject(myService)
myObject.getSomeStuff()
}
You should be able to call onResponse() by using:
every { get(any()) }
answers {
firstArg<MyService.Callback<MyServiceResponse>>().onResponse(aMyServiceResponse)
}
By the way, as you are using a callback, I guess that the implementation is asynchronous, so you'll probably need to use the coEvery / coAnswer variant.
HTH

How to do coVerifyOrder of livedata.postValue(any()) - It is returning io.mockk.MockKException: Failed matching mocking signature for

Scenario -
Hi I am new in testing using mockk. I want to test the order in which methods are being called in viewmodel. And I want to test livedata.postValue in verify block{} but mockk is giving an exception. Kindly also help me to understand the meaing of exception
MyViewModel.kt
fun doWork(showError: Boolean = false) {
launch {
val result = getImageUseCase.getImages()
if (!showError) {
withContext(uiDispatcher) {
liveDataResponse.postValue(LiveDataResult.success(Response(result)))
}
} else {
throw Exception("Unknown")
}
}
}
MyViewModelTest.kt
#Test
fun verifyOrderOfMethodExecution(){
coEvery { getImageUseCase.getImages() } returns 1
myViewModel.doWork()
coVerifyOrder {
getImageUseCase.getImages()
myViewModel.liveDataResponse.postValue(any())
}
}
Exception -
io.mockk.MockKException: Failed matching mocking signature for
SignedCall(retValue=, isRetValueMock=true, retType=class kotlin.Any, self=GetImageUseCase(usecase#1), method=getImages(Continuation), args=[Continuation at com.rahullohra.lab.MyViewModelTest$verifyOrderOfMethodExecution$2.invokeSuspend(MyViewModelTest.kt:79)], invocationStr=GetImageUseCase(usecase#1).getImages(continuation {}))
left matchers: [any()]

How to call a lambda callback with mockk

I create a mock of a class with mockk.
On this mock I now call a method that gets a lambda as a parameter.
This lambda serves as a callback to deliver state changes of the callback to the caller of the method.
class ObjectToMock() {
fun methodToCall(someValue: String?, observer: (State) -> Unit) {
...
}
}
How do I configure the mock to call the passed lambda?
You can use answers:
val otm: ObjectToMock = mockk()
every { otm.methodToCall(any(), any())} answers {
secondArg<(String) -> Unit>().invoke("anything")
}
otm.methodToCall("bla"){
println("invoked with $it") //invoked with anything
}
Within the answers scope you can access firstArg, secondArg etc and get it in the expected type by providing it as a generic argument. Note that I explicitly used invoke here to make it more readable, it may also be omitted.
I had to look for a bit more example for the callback and found some example in Kotlin Test with Mockk. In my case, it's a bit more specific.
I wanted to check and mock the onFailure and onSuccess case of a a custom callback implementation MyCustomCallback implementing the ListenableFutureCallback.
The code would look like that for my ExampleProducer class that would have a send function:
fun send(data: String) {
val responseFuture = kafkaTemplate.send(topic, data)
responseFuture.addCallback(MyCustomCallback())
}
So here who would the test go:
#Test
fun onFailureTest() {
kafkaTemplate: KafkaTemplate<String, String> = mockk()
val captureCallback = slot<ListenableFutureCallback<SendResult<String, String>>>()
every { callback.addCallback(capture(captureCallback)) } answers {
captureCallback.captured.onFailure(Throwable())
}
every { kafkaTemplate.send(any()) } returns callback
val prod: ExampleProducer = ExampleProducer()
prod.send("test")
// Then you can verify behaviour or check your captureCallback.captured
verify { kafkaTemplate.send(any()) }
assertNotNull(captureCallback.captured)
}
Maybe not exactly what you ask about, but you can use the funciton type for the mock:
val observerMock = mockk<(State) -> Unit>()