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

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

Related

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

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>()) }

Kotlin multiplatform: JobCancellationException: Parent job is Completed

I try to write a kotlin multiplatform library (android and ios) that uses ktor. Thereby I experience some issues with kotlins coroutines:
When writing tests I always get kotlinx.coroutines.JobCancellationException: Parent job is Completed; job=JobImpl{Completed}#... exception.
I use ktors mock engine for my tests:
client = HttpClient(MockEngine)
{
engine
{
addHandler
{ request ->
// Create response object
}
}
}
A sample method (commonMain module) using ktor. All methods in my library are written in a similar way. The exception occures if client.get is called.
suspend fun getData(): Either<Exception, String> = coroutineScope
{
// Exception occurs in this line:
val response: HttpResponse = client.get { url("https://www.google.com") }
return if (response.status == HttpStatusCode.OK)
{
(response.readText() as T).right()
}
else
{
Exception("Error").left()
}
}
A sample unit test (commonTest module) for the above method. The assertTrue statement is never called since the exception is thrown before.
#Test
fun getDataTest() = runTest
{
val result = getData()
assertTrue(result.isRight())
}
Actual implementation of runTest in androidTest and iosTest modules.
actual fun<T> runTest(block: suspend () -> T) { runBlocking { block() } }
I thought when I use coroutineScope, it waits until all child coroutines are done. What am I doing wrong and how can I fix this exception?
you can't cache HttpClient of CIO in client variable and reuse, It would be best if change the following code in your implementation.
val client:HttpClient get() = HttpClient(MockEngine) {
engine {
addHandler { request ->
// Create response object
}
}
}
The library must be updated, this glitch is in the fix report here: https://newreleases.io/project/github/ktorio/ktor/release/1.6.1
The problem is that you cannot use the same instance of the HttpClient. My ej:
HttpClient(CIO) {
install(JsonFeature) {
serializer = GsonSerializer()
}
}.use { client ->
return#use client.request("URL") {
method = HttpMethod.Get
}
}

Kotlin ?.let + ?:run + CompletableFuture unexpected behaviour

Here is the code, it runs as expected, no exception
fun main() {
var mayBeEmptyString: String?
mayBeEmptyString = "1";
mayBeEmptyString?.let {
println("Inside let")
} ?: run {
throw RuntimeException("Inside run")
}
}
Output:
Inside let
And here is the code that I am not able to understand how it works:
fun main() {
var mayBeEmptyString: String?
mayBeEmptyString = "1";
mayBeEmptyString?.let {
// println("Inside let")
CompletableFuture.runAsync{ println("Inside let")}.join()
} ?: run {
throw RuntimeException("Inside run")
}
}
Output:
Inside let
Exception in thread "main" java.lang.RuntimeException: Inside run
at com.test.TestKt.main(test.kt:15)
at com.test.TestKt.main(test.kt)
Can anyone explain what is going on here? Thank you.
runAsync is meant for running a task that doesn't return a value, so you get a CompletableFuture<Void>, and attempting to read its value with get or join will give you null.
You then make this null result of join the result of your let block, which will cause your run block to be executed.
Because CompletableFuture.join() return null value cause
mayBeEmptyString?.let {
// println("Inside let")
CompletableFuture.runAsync{ println("Inside let")}.join()
}
will be null
and run { } will be executed

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()]

Kotlin + Mockito + NullPointerException thrown when stubbing

Today I stumbled across a situation which I do not understand, possibly because of lack of insight into how mockito and mockito-kotlin work internally.
Given the code below, from my Kotlin beginner perspective, I have two pretty similar interface-methods. One returns Boolean, one String. Both are suspend functions in my example as in my real world situation my functions are too.
class ITestInterface {
suspend fun returnBoolean(): Boolean {
return true
}
suspend fun returnSomeString() : String {
return "String"
}
}
#Test
fun demoTest() {
val implMock = mock<ITestInterface> {
on {
runBlocking {
returnSomeString()
}
} doReturn "Hello"
on {
runBlocking {
returnBoolean()
}
} doReturn false
}
}
My observation is, when I run the test, like depicted above, I get the following error Message
com.nhaarman.mockitokotlin2.MockitoKotlinException: NullPointerException thrown when stubbing.
This may be due to two reasons:
- The method you're trying to stub threw an NPE: look at the stack trace below;
- You're trying to stub a generic method: try `onGeneric` instead.
at com.nhaarman.mockitokotlin2.KStubbing.on(KStubbing.kt:72)
at com.rewedigital.fulfillment.picking.components.substitute.DemoTest.demoTest(DemoTest.kt:30)
[...]
Experiments showed that
the behavior is only shown by the Boolean returning function, not by returnSomeString()
removing the suspend keyword fro the returnBoolean function makes the error go away
using onGeneric as suggested in the error message also makes the error go away
Could anybody explain why this is happening? To what extend do we have to do with generics here? And what would be the correct way of solving the issue in our real application? Having a bunch of on {} and some onGeneric {} ?
Thanks for your help!
You should use the onBlocking method to properly mock the suspend function
Please try the following code:
#Test
fun demoTest() {
val implMock = mock<ITestInterface> {
onBlocking {
returnSomeString()
} doReturn "Hello"
onBlocking {
returnBoolean()
} doReturn false
}
runBlocking {
// Execute your code here
assertThat(implMock.returnSomeString()).isEqualTo("Hello")
assertThat(implMock.returnBoolean()).isEqualTo(false)
}
}