How to verify a top level function was called with Mockk? - kotlin

How to verify that a top level (static) function was called in a test with MockK?
Simple approach like:
verify { someTopLevelFunction("some text") }
results in io.mockk.MockKException: can't find stub kotlin.Unit.

You would mockk the same way you mockk extension functions https://mockk.io/#extension-functions
In practice generally:
mockkStatic(ClassNameWhereFunctionIsLocated::class)
verify {
someTopLevelFunction("some text")
}

Related

Kotlin: How to verify an extension function is called on a mock

Say I have a Java class Metrics. I defined some extension functions on Metrics in Kotlin
fun Merics.expose(name: String, value: Number) {
// do something
}
Note that the Java class Metrics also has a method called expose but with different signature.
I created a test where I mocked a metrics objects and call a code path where the extension function expose should be called. But how can I verify that those extension functions are invoked?
I tried to use mockk and mockito-kotlin, none of them seem to know that metrics object has a new function called expose with different signatures.
You can not verify that the extension function is called on your mock, as it is not part of that class. The extension function is just a top-level function with a receiver (in your case an instance of Metrics).
But you can still verify that the extension function was called in your code
You can do this using mockkStatic.
You are passing the the path of the (generated) extension function. Let's assume you created your Metrics extension function in package org.com. The extension class should get generated in: com.org.MericsExtensionKt.
A test that wants to verify the call to your extension function could look like:
#Test
fun check_metrics_expose_extension_was_called() {
mockkStatic("com.org.MericsExtensionKt")
// call your function that is calling Metrics.expose()
// classUnderTest.someFunction()
// this verifies a call to the extension function and their parameters
verify { any<Metrics>().expose(name = any(), value = any()) }
}

How to mock a constructor with a spy?

I am currently trying to test my Exposed Kotlin code. I have a table that follows the form
object Foo: Table() {
*parameters*
}
and a method that looks something like
fun addNewFoo(){
Foo.insert { ... }
}
I'm testing addNewFoo and I want to verify the insert occurred, ideally using something like
verify { FooSpy.insert { ... } }
How do I mock the Foo table to be a spy so I can verify the call occurred, or what other approach should I take to verify this method being called?
You can first mock your singleton Foo class using mockkObject() and then verify. Here is the code:
mockkObject(Foo) // mock the object
addNewFoo() // call function that we're testing
verify { Foo.insert(any()) } // verify
There is discussion of ways to go about it: https://github.com/JetBrains/Exposed/issues/317
There seems to be no real intended way for testing but making small test tables in a test data base is the closest you can get.

How to mock Kotlin's List.forEach?

For the given code below, in Kotlin, it's not possible to execute the function forEach (or anything similar, map, filter, so on...) because BarList is mocked. So the native implementation of forEach and relatives are not being called. After a bit of search on the internet I came with this:
public class BarList<E> extends AbstractList<E> implements OrderedBarCollection<E> {
//...
}
//...
val mockedList: BarList<Foo> = mockBarList()
val fooList = listOf(Foo())
`when`(mockedList.iterator()).thenReturn(fooList.iterator())
`when`(mockedList.size).thenReturn(fooList.size)
com.nhaarman.mockito_kotlin
.doCallRealMethod()
.`when`(mockedList)
.forEach(Mockito.any<Consumer<Foo>>()) //Attempt to call the Consumer.
mockedList.forEach { foo ->
//Not executing
}
I tried this above based on the answer of this question: https://stackoverflow.com/a/49407513/2430555
I also tried:
com.nhaarman.mockito_kotlin.doCallRealMethod().`when`(mockedList).forEach(any())
But it's causing:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
//...
The definition of forEach in the Kotlin source code is:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
I think I should replace any() with something that matches action: (T) -> Unit, but I am not sure how to do this.
I don't mind to use interactor if needed, but I need to at least make forEach run as expected. Could you guys please help me?
Regards,
Pedro
The solution is to use thenAnswer instead of thenReturn for the mocked list.
`when`(mockedList.iterator()).thenAnswer { fooList.iterator() }
Reason:
Author: Tobias Berger
an iterator is only good for going through the list once. Therefore
you usually get a new one every time you call the iterator() function.
If you mock that with thenReturn(messageList.iterator()) , it will
just call that once on messageList and reuse that iterator instance
every time you try to get one for your mock. Once your first loop over
this iterator is finished, it will always say it has no more items.
With thenAnswer you define a supplier that is called each time your
mocked function is used, providing a new iterator for each call (as
would be expected)
I think you cannot mock extension funcitons at all, while they are not members of target class.
forEach is Just outer helper for Iterable
In this case you will be still calling usual forEach of kotlin on fooList.
And i don't understand what is the motivation to mock collections especially substitute iterator of mocking OrderedBarCollection with simple ArrayList (listOf), what is requirement to do it?

KClass::memberExtensionFunctions always be empty

Code
import kotlin.reflect.full.*
class FooBar(val bar: String)
fun FooBar.baz(): Unit {println(this.bar)}
fun main(args: Array<String>) {
FooBar::class.declaredMemberExtensionFunctions.forEach {
println(it)
}
FooBar::class.memberExtensionFunctions.forEach {
println(it)
}
}
Output is empty
This is because declaredMemberExtensionFunctions only returns extension functions that are declared inside a class (as seen in the docs) and FooBar.baz() is a top level declaration (So it is not declared inside FooBar.
class FooBar(val bar: String) {
fun FooBar.baz(): Unit {
println(this.bar)
}
}
While I imagine this is not what you want, structuring the extension function like this would make your main method output lines.
TLDR: You aren't going to be able to do this. Because extension functions can be declared everywhere, you are limited in what the reflection system can do for you.
There is a thread on kotlinlang.org that covers this exact question and why it is not possible.
Essentially, Kotlin's declaredMemberExtensionFunctions function is able to list extension functions which are declared as part of the class, not externally. The docs state:
Returns extension functions declared in this class.
And of course, memberExtensionFunctions behaves similarly:
Returns extension functions declared in this class and all of its superclasses.
Here's what #Yole says in that thread as to why this is not possible:
The task of finding all extension functions for Foo is equivalent to finding all methods which have Foo as the first parameter. Neither of these is possible without accessing every single class in your application through reflection.
#Yole is on here, he might be able to provide a more authoritative answer for you.

Spock and internal kotlin function

I am having trouble with using internal kotlin functions in my Spock tests. Here's short snippet of my spock test:
private def preconditions = new MonetaryPreconditions()
private def usdMonetary = new Monetary(BigDecimal.ZERO, Currency.USD)
def "should throw nothing because Monetaries currencies are same"(){
when:
preconditions.checkMonetariesCurrencies(usdMonetary , usdMonetary )
then:
noExceptionThrown()
}
and my MonetaryPreconditions class:
internal object MonetaryPreconditions {
internal fun checkMonetariesCurrencies(monetary1: Monetary, monetary2: Monetary) {
if (monetary1.currency != monetary2.currency) {
throw CurrencyMismatchException(arrayOf(monetary1.currency, monetary2.currency), "Compared currencies does not match: " + monetary1.currency
+ " , " + monetary2.currency)
}
}
}
My test fails with a stacktrace:
groovy.lang.MissingMethodException: No signature of method: touk.recruitment.parkandrest.parkingmanagement.core.monetary.MonetaryPreconditions.checkMonetariesCurrencies() is applicable for argument types: (touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary, touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary) values: [touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary#7c417213, ...]
The problem lies in internal visibility of my checkMonetariesCurrencies function. If I change it to public it works just fine, however I do want this to be module private. How can I achieve that with Spock?
Other information about my project:
Test class and MonetaryPreconditions have same package.
I am using Maven.
Test class and MonetaryPreconditions are of course in the same module.
I just ran into the same issue, and the workaround I used (suggested by an experienced coworker of mine) was to write a wrapper class in Kotlin (in the same package as the class under test (CUT); I placed the source code file in the test/kotlin folder) and just forward function calls to the CUT. I then used the wrapper class in my groovy unit test code.
Further, calling functions defined within an object in Kotlin from another programming language requires you to access the object's INSTANCE variable, e.g.
MonetaryPreconditions.INSTANCE.myfunction
In your case, the wrapper may look as follows:
package com.yourpackage
object MonetaryPreconditionsWrapper{
fun checkMonetariesCurrencies(monetary1: Monetary, monetary2: Monetary){
MonetaryPreconditions.checkMonetariesCurrencies(monetary1, monetary2)
}
}
Now you can test the MonetaryPreconditions.checkMonetariesCurrencies function by simply calling the wrapper function from the groovy code as follows:
MonetaryPreconditionsWrapper.INSTANCE.checkMonetariesCurrencies(monetary1, monetary2)
Thanks you Giuseppe for your answer. However for me, Spock didn't see the wrapper as it thought it was a property of the test class and threw a groovy.lang.MissingPropertyException. I had add this to build.gradle:
compileTestGroovy.classpath += files(compileTestKotlin.destinationDir)
Taken from here: https://localcoder.org/test-classes-in-groovy-dont-see-test-classes-in-kotlin