How to enter dependencies in ktor Application

The documentation talks about dependency injection, but doesn't really show how to do it.

The documentation is also unfilled and has a bunch of place owners: http://ktor.io/getting-started.html

I tried to create my main function in such a way that it takes a parameter (which is my dependency), but this failed on the testing side when I call withTestApplication. I looked at the application code and saw that the application is accepting a configuration object, but I have no idea how I can modify this configuration object to inject some dependencies into it.

package org.jetbrains.ktor.application

/**
 * Represents configured and running web application, capable of handling requests
 */
class Application(val environment: ApplicationEnvironment) : ApplicationCallPipeline() {
    /**
     * Called by host when [Application] is terminated
     */
    fun dispose() {
        uninstallAllFeatures()
    }
}

/**
 * Convenience property to access log from application
 */
val Application.log get() = environment.log

In the test code with help withTestApplication, I have something similar to the following:

@Test
internal fun myTest() = withTestApplication (Application::myMain)

withTestApplication , myMain (, .)

Update:

, , - , , , / .

+4
2

Ktor . DI, , , , Guice. :

fun Application.module() {
  Guice.createInjector(MainModule(this))
}

// Main module, binds application and routes
class MainModule(private val application: Application) : AbstractModule() {
    override fun configure() {
        bind(Application::class.java).toInstance(application)
        ... other bindings ...
    }
}

Guice . . :

class Hello @Inject constructor(application: Application) {
  init {
    application.routing {
        get("/") {
            call.respondText("Hello")
        }
    }
  }
}

:

bind(Hello::class.java).asEagerSingleton()

asEagerSingleton , Guice , .

+5

1) prod test:

val prodModule = module {
    single<IFirstService> { RealFirstService() }
    single<ISecondService> { RealSecondService() }
}

val testModule = module {
    single<IFirstService> { FakeFirstService() }
    single<ISecondService> { FakeSecondService() }
}

2) DI :

fun main(args: Array<String>) {
    startKoin(listOf(prodModule))
    embeddedServer(Netty, commandLineEnvironment(args)).start(true)
}

3) :

fun Application.apiModule() {
    val firstService: IFirstService by inject()
    val secondService: ISecondService by inject()
    ...
    routing {
        someApi(inject(), inject())
    }
}

4) (). testModule :

fun testApp(test: TestApplicationEngine.() -> Unit) {
    withTestApplication({
        ... // configure your test app here

        stopKoin() // Need to stop koin and restart after other tests
        startKoin(listOf(testModule)) // Init with test DI

        apiModule() // Run you application
    })
}

// And run tests
@Test
fun 'get events'() = testApp {
    // do tests
}

!

0

Source: https://habr.com/ru/post/1685556/


All Articles