BAEL-1462 Kotlin DI with Kodein (#3544)

* BAEL-1462 Kotlin DI with Kodein

* BAEL-1462 Kotlin DI with Kodein

* applied editor's suggestions
* removed unnecessary curly braces

* Moved kodein files into core-kotlin as per editor's review

* Using assertj instead of junit assertions as per editor's instruction
This commit is contained in:
Denis 2018-02-27 04:51:55 +03:00 committed by KevinGilmore
parent 30285c1c18
commit ef1b033b78
7 changed files with 220 additions and 1 deletions

View File

@ -76,7 +76,18 @@
<artifactId>mockito-kotlin</artifactId>
<version>${mockito-kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependency>
<dependency>
<groupId>com.github.salomonbrys.kodein</groupId>
<artifactId>kodein</artifactId>
<version>${kodein.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -189,11 +200,13 @@
<kotlin-reflect.version>1.1.2</kotlin-reflect.version>
<kotlinx.version>0.15</kotlinx.version>
<mockito-kotlin.version>1.5.0</mockito-kotlin.version>
<kodein.version>4.1.0</kodein.version>
<junit.jupiter.version>5.0.0</junit.jupiter.version>
<junit.platform.version>1.0.0</junit.platform.version>
<junit.vintage.version>4.12.0</junit.vintage.version>
<junit4.version>4.12</junit4.version>
<assertj.version>3.9.1</assertj.version>
</properties>
</project>

View File

@ -0,0 +1,3 @@
package com.baeldung.kotlin.kodein
class Controller(private val service : Service)

View File

@ -0,0 +1,3 @@
package com.baeldung.kotlin.kodein
interface Dao

View File

@ -0,0 +1,3 @@
package com.baeldung.kotlin.kodein
class JdbcDao : Dao

View File

@ -0,0 +1,3 @@
package com.baeldung.kotlin.kodein
class MongoDao : Dao

View File

@ -0,0 +1,3 @@
package com.baeldung.kotlin.kodein
class Service(private val dao: Dao, private val tag: String)

View File

@ -0,0 +1,191 @@
package com.baeldung.kotlin.kodein
import com.github.salomonbrys.kodein.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
class KodeinUnitTest {
class InMemoryDao : Dao
@Test
fun whenSingletonBinding_thenSingleInstanceIsCreated() {
var created = false
val kodein = Kodein {
bind<Dao>() with singleton {
created = true
MongoDao()
}
}
assertThat(created).isFalse()
val dao1: Dao = kodein.instance()
assertThat(created).isTrue()
val dao2: Dao = kodein.instance()
assertThat(dao1).isSameAs(dao2)
}
@Test
fun whenFactoryBinding_thenNewInstanceIsCreated() {
val kodein = Kodein {
bind<Dao>() with singleton { MongoDao() }
bind<Service>() with factory { tag: String -> Service(instance(), tag) }
}
val service1: Service = kodein.with("myTag").instance()
val service2: Service = kodein.with("myTag").instance()
assertThat(service1).isNotSameAs(service2)
}
@Test
fun whenProviderBinding_thenNewInstanceIsCreated() {
val kodein = Kodein {
bind<Dao>() with provider { MongoDao() }
}
val dao1: Dao = kodein.instance()
val dao2: Dao = kodein.instance()
assertThat(dao1).isNotSameAs(dao2)
}
@Test
fun whenTaggedBinding_thenMultipleInstancesOfSameTypeCanBeRegistered() {
val kodein = Kodein {
bind<Dao>("dao1") with singleton { MongoDao() }
bind<Dao>("dao2") with singleton { MongoDao() }
}
val dao1: Dao = kodein.instance("dao1")
val dao2: Dao = kodein.instance("dao2")
assertThat(dao1).isNotSameAs(dao2)
}
@Test
fun whenEagerSingletonBinding_thenCreationIsEager() {
var created = false
val kodein = Kodein {
bind<Dao>() with eagerSingleton {
created = true
MongoDao()
}
}
assertThat(created).isTrue()
val dao1: Dao = kodein.instance()
val dao2: Dao = kodein.instance()
assertThat(dao1).isSameAs(dao2)
}
@Test
fun whenMultitonBinding_thenInstancesAreReused() {
val kodein = Kodein {
bind<Dao>() with singleton { MongoDao() }
bind<Service>() with multiton { tag: String -> Service(instance(), tag) }
}
val service1: Service = kodein.with("myTag").instance()
val service2: Service = kodein.with("myTag").instance()
assertThat(service1).isSameAs(service2)
}
@Test
fun whenInstanceBinding_thenItIsReused() {
val dao = MongoDao()
val kodein = Kodein {
bind<Dao>() with instance(dao)
}
val fromContainer: Dao = kodein.instance()
assertThat(dao).isSameAs(fromContainer)
}
@Test
fun whenConstantBinding_thenItIsAvailable() {
val kodein = Kodein {
constant("magic") with 42
}
val fromContainer: Int = kodein.instance("magic")
assertThat(fromContainer).isEqualTo(42)
}
@Test
fun whenUsingModules_thenTransitiveDependenciesAreSuccessfullyResolved() {
val jdbcModule = Kodein.Module {
bind<Dao>() with singleton { JdbcDao() }
}
val kodein = Kodein {
import(jdbcModule)
bind<Controller>() with singleton { Controller(instance()) }
bind<Service>() with singleton { Service(instance(), "myService") }
}
val dao: Dao = kodein.instance()
assertThat(dao).isInstanceOf(JdbcDao::class.java)
}
@Test
fun whenComposition_thenBeansAreReUsed() {
val persistenceContainer = Kodein {
bind<Dao>() with singleton { MongoDao() }
}
val serviceContainer = Kodein {
extend(persistenceContainer)
bind<Service>() with singleton { Service(instance(), "myService") }
}
val fromPersistence: Dao = persistenceContainer.instance()
val fromService: Dao = serviceContainer.instance()
assertThat(fromPersistence).isSameAs(fromService)
}
@Test
fun whenOverriding_thenRightBeanIsUsed() {
val commonModule = Kodein.Module {
bind<Dao>() with singleton { MongoDao() }
bind<Service>() with singleton { Service(instance(), "myService") }
}
val testContainer = Kodein {
import(commonModule)
bind<Dao>(overrides = true) with singleton { InMemoryDao() }
}
val dao: Dao = testContainer.instance()
assertThat(dao).isInstanceOf(InMemoryDao::class.java)
}
@Test
fun whenMultiBinding_thenWorks() {
val kodein = Kodein {
bind() from setBinding<Dao>()
bind<Dao>().inSet() with singleton { MongoDao() }
bind<Dao>().inSet() with singleton { JdbcDao() }
}
val daos: Set<Dao> = kodein.instance()
assertThat(daos.map { it.javaClass as Class<*> }).containsOnly(MongoDao::class.java, JdbcDao::class.java)
}
@Test
fun whenInjector_thenWorks() {
class Controller2 {
private val injector = KodeinInjector()
val service: Service by injector.instance()
fun injectDependencies(kodein: Kodein) = injector.inject(kodein)
}
val kodein = Kodein {
bind<Dao>() with singleton { MongoDao() }
bind<Service>() with singleton { Service(instance(), "myService") }
}
val controller = Controller2()
controller.injectDependencies(kodein)
assertThat(controller.service).isNotNull
}
}