How mock Kotlin extension function in interface? - kotlin

I have an extension function for interface like the following:
import javax.jms.ConnectionFactory
fun ConnectionFactory.foo() {
println("do some stuff")
}
How can I mock the function foo?
Please note, I have seen approaches for classes and objects in http://mockk.io/#extension-functions, but it does not work. I have tried this one:
import io.mockk.classMockk
import io.mockk.every
import org.junit.Test
import javax.jms.ConnectionFactory
class ExtensionFunctionTest {
#Test
fun mockExtensionFunction() {
val connectionFactory = classMockk(ConnectionFactory::class)
every { connectionFactory.foo() } returns println("do other stuff")
connectionFactory.foo()
}
}
It throws exception:
io.mockk.MockKException: Missing calls inside every { ... } block.

According to the documentation in case of module wide extension functions you need to staticMock "hidden" class created for an extension function.
Here is an example (assuming the file name is com/sample/extmockingtest/SampleTest.kt):
fun <T> Iterable<T>.foo(): String = "do some stuff"
class ExtensionFunctionTest {
#Test
fun mockExtensionFunction() {
val itMock = classMockk(Iterable::class);
staticMockk("com.sample.extmockingtest.SampleTestKt").use {
every {
itMock.foo()
} returns "do other stuff"
assertEquals("do other stuff", itMock.foo())
verify {
itMock.foo()
}
}
}
}

Related

Why is the Result object wrapped in another Result?

When using a ParameterizedTest annotation with a source containing an "Result" type class, the type of the parameter is not the same as the argument.
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream
class testTest() {
companion object {
#JvmStatic
fun streamOfArguments(): Stream<Arguments?>? {
return Stream.of(
Arguments.of(Result.success(true)) // Type Result<Boolean>
)
}
}
#ParameterizedTest
#MethodSource("streamOfArguments")
fun testArgumentParameter(
argumentFromStream: Result<Result<Boolean>> // Wrapped in an additional successful `Result`
) {
println(argumentFromStream::class)
argumentFromStream.onSuccess{
println(it)
}
}
}

How can Mockito mock a Kotlin `use` (aka try-with-resource)?

If I were trying to add mocks to the following code (where the MyTypeBuilder is mocked to return a mocked MyType - which implements Closeable):
myTypeBuilder.build(myTypeConfiguration).use { myType ->
myType.callMyMethod()
}
Then trying to verify interactions with myType.callMethod() something like:
myType: MyType = mock()
myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
doMethodCall()
verify(myType, times(1)).callMyMethod()
I'm getting errors:
Wanted but not invoked:
myType.callMethod()
-> at package.me.MyType.callMyMethod(MyType.kt:123)
However, there was exactly 1 interaction with this mock:
myType.close()
-> at kotlin.io.CloseableKt.closeFinally(Closeable.kt:57)
So it appears that I need to add a whenever to execute the use block, but I'm not sure what that should look like. Alternatively, the use should act like a Mockito spy rather than a mock, but then allow mocking on the other methods.
I tried to reconstruct the error by writing the following code which is basically what you wrote in your question plus some println statements and some boilerplate to make it runnable:
import org.junit.jupiter.api.Test
import org.mockito.Mockito.*
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.Closeable
open class MyTypeBuilder {
open fun build(config: Any): MyType {
println("build")
return MyType()
}
}
open class MyType : Closeable {
fun callMyMethod() {
println("callMyMethod")
}
override fun close() {
println("close")
}
}
val myTypeConfiguration: Any = "heyho"
fun call(myTypeBuilder: MyTypeBuilder) {
myTypeBuilder.build(myTypeConfiguration).use { myType ->
println("call")
myType.callMyMethod()
}
}
class MockAndUseTest {
#Test
fun test() {
val myType: MyType = mock()
val myTypeBuilder: MyTypeBuilder = mock()
whenever(myTypeBuilder.build(any())).thenReturn(myType)
call(myTypeBuilder)
verify(myType, times(1)).callMyMethod()
}
}
When I run the test case test, it succeeds and is green.
So, unfortunately whatever may cause your problem, it is not contained in the details given by your question.

How can I check Koin modules while using injection parameters?

I would like to check my configuration by using the checkModules() method provided by koin-test as explained here.
However, I am using injection parameters and my test fails with an exception:
org.koin.core.error.NoParameterFoundException: Can't get parameter value #0 from org.koin.core.parameter.DefinitionParameters#3804648a
Here is a simple test to demonstrate the issue:
import org.junit.Test
import org.koin.dsl.koinApplication
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.check.checkModules
class TestCase : KoinTest {
#Test
fun checkModules() {
koinApplication {
modules(
module { factory { (msg: String) -> Message(msg) } }
)
}.checkModules()
}
data class Message(val message: String)
}
Is there a way to make this work? How could I provide the missing parameter?
You need to pass this parameter to your test, like this:
class TestCase : KoinTest {
#Test
fun checkModules() {
koinApplication {
modules(module { factory { (msg: String) -> Message(msg) } })
}.checkModules {
create<Message> { parametersOf("testMessage") }
}
}
data class Message(val message: String)
}
Example from Koin repository: CheckModulesTest.kt#L156
My issue with the same question: Issue

Equivalent of doReturn(x).when(y)... in mockk?

I am looking for a mockk equivalent of doReturn(...).when(...).*
I am working on writing some unit tests (testing contracts) that involves a lot of system classes and so need to intercept the methods that I don't control and return some call backs (which the method in code would have eventually returned). In mockito, I could do something like doReturn(...).when(...).*
I Wasn't able to find a similar thing in mockK. Seems like every{} always runs the block before answers or returns.
class Vehicle: Listener {
fun displayCar(listener:Listener){
OtherClass().fetchCar(listener)
}
override fun showCarSuccessful() {
//do something
}
}
class OtherClass {
//assume its an outside function that returns nothing but invokes a method of listener call back
fun fetchCar(listener: Listener) {
//... Some system level operations that I don't have control to generate mock objects but in the test I want to use the listener to call some method so that I can
// test some contracts
listener.showCarSuccessful()
}
}
class Tests {
#Test
fun testCarSuccess() {
val listener: Listener = mockk(relaxed = true)
val vehicle = Vehicle()
//also tried with mockkClass and others
val other: OtherClass = mockk(relaxed = true)
every { other.fetchCar(listener) } returns {listener.showCarSuccessful()}
vehicle.displayCar(listener)
//do some verification checks here
}
}
interface Listener {
fun showCarSuccessful()
}
The every{} block is your when clause. You can set up multiple conditions for returning different results. See the example of setting up fixed returns and performing progrommatic answers
import io.mockk.MockKException
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
class MyClass {
fun add(operand1: Int, operand2: Int): Int {
TODO()
}
}
class MockkTest {
#Test
fun testMocking() {
val myClassMock = mockk<MyClass> {
every { add(1, 2) } returns 3 // Set behaviour
every { add(2, 2) } returns 4 // Set behaviour
every { add(3, 4)} answers {args[0] as Int * args[1] as Int} // Programmatic behaviour
}
Assertions.assertEquals(3, myClassMock.add(1, 2))
Assertions.assertEquals(4, myClassMock.add(2, 2))
Assertions.assertEquals(12, myClassMock.add(3, 4))
Assertions.assertThrows(MockKException::class.java) {
myClassMock.add(5, 6) // This behaviour has not been set up.
}
}
}
But, in your example in particular, I find this line:
every { other.fetchCar(listener) } returns listener.showCarSuccessful()
very strange. First it is not doing what you think it is doing - it is going to make that call as you set this behaviour up you are telling your mock to return the result of that call, not to do that cal. To do what you want to do, you should rather do this:
every { other.fetchCar(listener) } answers {listener.showCarSuccessful()}
But even then, this line is setting up the mock behaviour after you have called your class under test - set up your mock behaviour first.
Also, it is strange that you are setting up side effects in a top level mock in a nested mock. Surely for testing your Vehicle class all you want to do is verify that its inner class was called with the correct arguments. Also, how does Vehicle get a reference to your OtherClass mock, it is instantiating a new one and calling that function.
Here is an attempt to make your example work:
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Test
interface Listener {
fun showCarSuccessful()
}
class Vehicle(val other: OtherClass) : Listener {
fun displayCar(listener: Listener) {
other.fetchCar(listener)
}
override fun showCarSuccessful() {
//do something
}
}
class OtherClass {
//assume its an outside function that returns nothing but invokes a method of listener call back
fun fetchCar(listener: Listener) {
}
}
class VehicleTest{
#Test
fun testDisplayCar(){
val listener: Listener = mockk(relaxed = true)
val other: OtherClass = mockk(relaxed = true) //also tried with mockkClass and others
val vehicle = Vehicle(other)
vehicle.displayCar(listener)
verify{ other.fetchCar(listener) }
}
}
Even this I think is maybe still a bit off - I suspect that the listener you want Vehicle to pass to OtherClass is itself, not an argument...
You should also then write a separate test for OtherClass to make sure it does what you expect it to when you call fetchCar

How do you Mockk a Kotlin top level function?

Mockk allows mocking static functions, but how does one mock a Kotlin top level function?
For example, if I have a Kotlin file called HelloWorld.kt, how do I mock the sayHello() function?
HelloWorld.kt
fun sayHello() = "Hello Kotlin!"
The following syntax has worked to me.
mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)
I'm surprised there is nothing on the jvm-stdlib yet for this.
Edit:
This overload has now been introduced officially:
https://github.com/mockk/mockk/pull/518
mockkStatic(::sayHello)
There is way to mockk a top level function:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
You just need to know which file this function goes. Check in JAR or stack trace.
To add on previous answers this is working:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
Where mockStatic takes as an argument "package_name:class_file_name"
But to simplify the mockStatick call you can give your file a name for the compiler with #file:JvmName directly in the file.
HelloWorld.kt
#file:JvmName("hello")
fun sayHello() = "Hello Kotlin!"
HelloWorldTest.kt
mockkStatic("pkg.hello")
every { fun() } returns 5
More detailed explication on why this is necessary and other examples here:https://blog.kotlin-academy.com/mocking-is-not-rocket-science-mockk-advanced-features-42277e5983b5
Building on #Sergey's answer:
You could have the actual implementation of the sayHello() function in a variable that's then the default value of a function parameter to sayHello().
This example works:
package tests
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
val sayHelloKotlin = { "Hello Kotlin!" }
fun sayHello(producer: () -> String = sayHelloKotlin): String = producer()
class Tests {
interface Producer {
fun produce(): String
}
#Test
fun `Top level mocking`() {
val mock = mockk<Producer>()
every { mock.produce() } returns "Hello Mockk"
val actual = sayHello(mock::produce)
Assertions.assertEquals(actual, "Hello Mockk")
}
}
The problem with this is that you're changing production code just to cater for testing, and it feels contrived.
This code doesn't work for me with mockk version 1.10.0 but works well in 1.11.0 (of course need to change mockkStatic(::bar) )
Utils.kt
#file:JvmName("UtilsKt")
package com.example.myapplication
fun foo(): Boolean {
return bar()
}
fun bar():Boolean {
return false
}
Test
#RunWith(RobolectricTestRunner::class)
#Config(sdk = [Build.VERSION_CODES.O_MR1])
class ExampleUnitTest {
#Test
fun addition_isCorrect() {
mockkStatic("com.example.myapplication.UtilsKt")
every { bar() } returns true
assertTrue(foo())
}
}