Can Mockito be used to match parameters that are functions in Kotlin? - kotlin

I have a function with a prototype similar to:
class objectToMock {
fun myFunc(stringArg: String, booleanArg: Boolean = false, functionArg: (String) -> Any = { 0 }): String
}
I'd like to be able to stub myFunc but can't figure out how to. Something like
#Mock
lateinit var mockedObject: ObjectToMock
#Before
fun setup() {
MockitoAnnotations.initMocks(this)
`when`(mockedObject.myFunc(anyString(), anyBoolean(), any())).thenReturn("")
}
Using any() and notNull() both lead to java.lang.IllegalStateException: any() must not be null

The solution here is to use anyOrNull from https://github.com/nhaarman/mockito-kotlin, or implement that helper yourself.

Mockito often returns null when calling methods like any(), eq() etcetera. Passing these instances to methods that are not properly mocked, can cause NullPointerExceptions
see: https://github.com/nhaarman/mockito-kotlin/wiki/Parameter-specified-as-non-null-is-null

you can add
mockedObject = ObjectToMock()
#Before It is the place to initialize.
#Test It is the place to test.you can call mockedObject.myFunc()

Related

How to create a member variable of Arrow Atomic in kotlin

Arrow-fx has a type Atomic which is similar to java AtomicRef but with an initial value, which means I don't need to check every time while accessing the atomic value whether it's null.
Here is a simple example
import arrow.fx.coroutines.*
suspend fun main() {
val count = Atomic(0)
(0 until 20_000).parTraverse {
count.update(Int::inc)
}
println(count.get())
}
Now I would like to create a class member variable with this type, but since it's only possible to initialize within a suspend function I would like to know the possibility here.
The easiest way is to make a "fake constructor" in the companion object.
public class Thingy private constructor(
val count: Atomic<Int>
) {
companion object {
suspend fun invoke() = Thingy(Atomic(0))
}
}
Now when you write Thingy(), you're actually calling the invoke function in Thingy.Companion. For that function there are no restrictions over suspending, so you can initialize Atomic as shown above.

How to avoid NPEs from default parameters in mocked classes?

Here's a simplified version of what I want to test with Mockito:
class UnderTest {
fun doSomething() {
foo.doAnything()
}
}
class Foo {
fun doAnything(bar: Bar = Bar())
}
class TestUnderTest {
#Mock
var underTest: UnderTest
#Test
fun testDoSomething() {
underTest.doSomething() // Causes NPE
}
}
UnderTest is being tested. Its dependencies, like foo, are mocked. However, when my tests call UnderTest.doSomething(), it crashes. doSomething() calls Foo.doAnything(), letting it fill in the null parameter with the default - and the code that runs in that default parameter initialization is outside of the control of my test, as it's inside the static, synthetic method created for the byte code.
Is there a magical Mockito solution to get around this very situation? If so, I would love to hear it. Otherwise, I believe the options I have are:
To use PowerMock or Mockk to be able to mock things Mockito can't
To change Foo to have two doAnything() methods; one would have zero parameters, would call Bar() and pass it to the other.
To change Foo.doAnything() to accept a nullable parameter, then to have the body of the function call Bar() and use it.

How to mock lambda with mockito in kotlin

I have a kotlin Android app. There is a function that loads compositions from the backend and returns them to a callback:
getCompositons(callback: (Array<Composition>) -> Unit)
How can I mock the callback using mockito. So that I then can do something like this:
var callback = //mockito mock
getCompositons(callback)
verify(callback, timeout(10000)).apply()
I read that lambda are matched to the java type function and therefore I assume apply could be the method invoked. Maybe I could mock a function and use that? But the Kotlin function interface only seems to have one return type, no parameters. java.util.Function says unresolved reference function.
Any help appreciated.
This is really no different to mocking any other type:
val callback = mock<(Array<Composition>) -> Unit>()
getCompositons(callback)
verify(callback)(any()) // Or verify(callback).invoke(any()) to be explicit
(In case you weren't aware of them, I'm using the mockito-kotlin bindings here.)
You can do that like this:
val function: Array<Composition>) -> Unit = {}
val callback = mock(function::class.java)
getCompositons(callback)
verify(callback)(any()) // or for example verifyNoInteractions(callback)
No extra libraries besides the standard mockito are needed
I solved here mocking the callback like this:
private val onNewUrl: (url: String) -> Boolean = mock {
on { mock(any()) } doReturn true
}
verify(onNewUrl).invoke(any())

How to inject dependency using koin in top level function

I have top-level function like
fun sendNotification(context:Context, data:Data) {
...//a lot of code here
}
That function creates notifications, sometimes notification can contain image, so I have to download it. I`m using Glide which is wrapped over interface ImageManager, so I have to inject it. I use Koin for DI and the problem is that I cannot write
val imageManager: ImageManager by inject()
somewhere in my code, because there is no something that implements KoinComponent interface.
The most obvious solution is to pass already injected somewhere else imageManager as parameter of function but I dont want to do it, because in most cases I dont need imageManager: it depends on type of Data parameter.
Easiest way is to create KoinComponent object as wrapper and then to get variable from it:
val imageManager = object:KoinComponent {val im: ImageManager by inject()}.im
Btw its better to wrap it by some function, for example I use
inline fun <reified T> getKoinInstance(): T {
return object : KoinComponent {
val value: T by inject()
}.value
}
So if I need instance I just write
val imageManager:ImageManager = getKoinInstance()
or
val imageManager = getKoinInstance<ImageManager>()
I did it in this way
fun Route.general() {
val repo: OperationRepo by lazy { GlobalContext.get().koin.get() }
...
}

How to write a package-level static initializer in Kotlin?

A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}