Dependency Injection

import org.junit.Before import org.junit.Test import kotlin.reflect.KClass import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNotSame import kotlin.test.assertSame class Bag( private val presents: List<String> = emptyList() ) { fun firstOrNull(filter: (String) -> Boolean) = presents.firstOrNull(filter) operator fun contains(present: String) = presents.contains(present) } class NaughtyChildList(names: List<String> = emptyList()) : List<String> by names class Child(val name: String, val wishList: List<String>) interface Santa { val bag: Bag fun choosePresentFor(child: Child): String? } class SantaImpl(override val bag: Bag, private val naughtyChildList: NaughtyChildList) : Santa { private val bagOfCharcoal = bag.firstOrNull { it == "bag of charcoal" } override fun choosePresentFor(child: Child): String? { if (naughtyChildList.contains(child.name)) { return bagOfCharcoal } return bag.firstOrNull { child.wishList.contains(it) } ?: bagOfCharcoal } } class RegistryTest { lateinit var registry: Registry @Before fun setup() { registry = Registry() } @Test fun whenRegisterSingletonClass_shouldInjectReturnIt() { registry.singleton { Bag() } val bag: Bag = registry.inject() assertNotNull(bag) } @Test fun whenUseInjectInSingleton_shouldInjectIt() { registry.normal { Bag() } registry.normal { NaughtyChildList() } registry.singleton<Santa> { SantaImpl(inject(), inject()) } val p: Santa = registry.inject() assertNotNull(p) } @Test fun whenUseInjectInSingleton_shouldInjectAndProperValuesShouldBeUsed() { val marek = Child("Marek", listOf("Book")) val michal = Child("Marek", listOf("Book")) registry.normal { Bag(listOf("Book", "Sister", "bag of charcoal")) } registry.normal { NaughtyChildList(listOf(marek.name)) } registry.singleton<Santa> { SantaImpl(inject(), inject()) } val p: Santa = registry.inject() assertEquals("bag of charcoal", p.choosePresentFor(marek)) assertEquals("bag of charcoal", p.choosePresentFor(michal)) } @Test fun whenInjectMoreSingleton_shouldBeTheSame() { registry.singleton { Bag() } val bag1: Bag = registry.inject() val bag2: Bag = registry.inject() assertSame(bag1, bag2) } @Test fun whenInjectMoreNormal_shouldntBeTheSame() { registry.normal { Bag() } val bag1: Bag = registry.inject() val bag2: Bag = registry.inject() assertNotSame(bag1, bag2) } @Test(expected = RegistryException::class) fun addSameNormalTwice_shouldThrowException() { registry.normal { Bag() } registry.normal { Bag() } } @Test(expected = RegistryException::class) fun addSameSingletonTwice_shouldThrowException() { registry.singleton { Bag() } registry.singleton { Bag() } } @Test(expected = RegistryException::class) fun addSameNormalAfterSingleton_shouldThrowException() { registry.singleton { Bag() } registry.normal { Bag() } } @Test(expected = RegistryException::class) fun addSameSingletonAfterNormal_shouldThrowException() { registry.normal { Bag() } registry.singleton { Bag() } } @Test(expected = RegistryException::class) fun whenClassNotExistsInRegistry_shouldThrowException() { val s: String = registry.inject() } } class RegistryException(message: String) : Exception(message) // Your code starts here //sampleStart class Registry(init: Registry.() -> Unit = {}) { init { init(this) } inline fun <reified T> singleton(noinline creator: Registry.() -> T) { TODO() } inline fun <reified T> normal(noinline creator: Registry.() -> T) { TODO() } inline fun <reified T> inject(): T { TODO() } } //sampleEnd
Save Restore Add own tests Switch to main Feedback

Your task is to implement a dependency injection framework like Koin or Injekt.

Check our usage in the tests (open with the plus above). It is based on the winning solution by Balázs Németh. Tests come from his repository.

Suggestions and explanations on how you can solve this problem here.


Previous
Next