For some reason I can't get constructor injection to work with Kodein.
This is the code to reproduce the exception:
import org.kodein.di.Kodein
import org.kodein.di.direct
import org.kodein.di.generic.bind
import org.kodein.di.generic.instance
import org.kodein.di.generic.provider
fun main(args: Array<String>) {
val kodein = Kodein {
bind<Test2>() to provider { Test2() }
bind<Test>() to provider { Test(instance()) }
}
val test = kodein.direct.instance<Test>()
}
class Test(val test2: Test2)
class Test2
The exception:
Exception in thread "main" org.kodein.di.Kodein$NotFoundException: No binding found for bind<Test>() with ? { ? }
Registered in this Kodein container:
at org.kodein.di.internal.KodeinContainerImpl.factory(KodeinContainerImpl.kt:174)
at org.kodein.di.KodeinContainer$DefaultImpls.factory$default(KodeinContainer.kt:33)
at org.kodein.di.KodeinContainer$DefaultImpls.provider(KodeinContainer.kt:80)
at org.kodein.di.internal.KodeinContainerImpl.provider(KodeinContainerImpl.kt:7)
at org.kodein.di.KodeinContainer$DefaultImpls.provider$default(KodeinContainer.kt:79)
at org.kodein.di.internal.DKodeinBaseImpl.Instance(DKodeinImpl.kt:33)
at AppKt.main(App.kt:20)
Why doesn't this work?
bind<Test2>() to provider { Test2() }
^^
This is Kotlin's to function, that generates a Pair, nothing to do with Kodein's DSL :p
Kodein's DSL uses with:
bind<Test2>() with provider { Test2() }
^^^^
Note that, when you are binding a type to itself, you can use a simpler syntax:
bind() from provider { Test2() }
Related
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.
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
This is my interface:
interface BlogService {
suspend fun tag() : JsonObject
}
Is it possible to create a dynamic proxy for the suspend method and run coroutine inside?
I can't use "Proxy.newProxyInstance" from jdk because I get a compilation error (suspend function should be run from another suspend function)
I had the same problem. And I think the answer is Yes. Here's what I figured out.
The following interface
interface IService {
suspend fun hello(arg: String): Int
}
is compiled into this
interface IService {
fun hello(var1: String, var2: Continuation<Int>) : Any
}
after compilation, there's no difference between a normal function and a suspend
function, except that the latter one has an additional argument of type
Continuation. Just return COROUTINE_SUSPENDED in the delegated
InvocationHandler.invoke if you actually want it supended.
Here's an example of creating an ISerivce instance via the java dynamic proxy
facility Proxy.newProxyInstance
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Proxy
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.coroutines.resume
fun getServiceDynamic(): IService {
val proxy = InvocationHandler { _, method, args ->
val lastArg = args?.lastOrNull()
if (lastArg is Continuation<*>) {
val cont = lastArg as Continuation<Int>
val argsButLast = args.take(args.size - 1)
doSomethingWith(method, argsButLast, onComplete = { result: Int ->
cont.resume(result)
})
COROUTINE_SUSPENDED
} else {
0
}
}
return Proxy.newProxyInstance(
proxy.javaClass.classLoader,
arrayOf(IService::class.java),
proxy
) as IService
}
I believe this code snippet is simple enough and self-explaining.
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()
}
}
}
}
I don't know if this is a bug or I'm just doing it wrong. I see nothing in the documentation that says that kodein factory bindings should be called in any way other than this:
class KodeinConfidenceTest {
#Test
fun testThatKodeinWorks() {
val kodein = Kodein {
bind<Dice>() with factory { sides: Int -> RandomDice(sides) }
}
val d:Dice = kodein.instance(5)
}
}
open class Dice
data class RandomDice(val sides:Int) : Dice()
...but this causes a NotFoundException
com.github.salomonbrys.kodein.Kodein$NotFoundException: No provider found for bind<Dice>("5") with ? { ? }
Registered in Kodein:
bind<Dice>() with factory { Int -> RandomDice }
You should never write kodein.instance(5), you should write kodein.instance(tag = 5)
Now you see your error. You are setting the tag (which differentiates bindings), not the argument to the factory.
In Kodein 4, the syntax is either kodein.with(5).instance() or kodein.factory<Int, Dice>().invoke(5)
I am currently developping Kodein 5 (no release schdule yet), in which this syntax will be changed to kodein.instance(arg = 5).
The accepted answer did not work for me in Kodein 5 (5.3.0). The below did.
class Die(val sides: Int)
fun main(args: Array<String>) {
val kodein = Kodein {
bind<Die>() with factory { sides: Int -> Die(sides) }
}
val die: Die by kodein.instance { 20 }
println("Sides ${die.sides}")
}