Hi, i’m migrating some tests to ktor 2.2.4 and hav...
# ktor
j
Hi, i’m migrating some tests to ktor 2.2.4 and having problems setting mocks to my routes. Is it possible to do it? I need too test the api responses only, don’t need to go all the way to external services.
Copy code
@Test
fun `can update passengers name 200 response`() = runTest {
    fun successUseCase(): UseCase<UpdatePassengersData, BusinessError, Unit> =
        object : UseCase<UpdatePassengersData, BusinessError, Unit> {
            override suspend fun invoke(command: Command<UpdatePassengersData>): Either<BusinessError, Unit> {
                return Either.Right(Unit)
            }
        }
    withTestApplication(withBookingTestApplication(successUseCase())) {
        with(
            handleRequest(<http://HttpMethod.Post|HttpMethod.Post>, "/updatePassengers") {
                addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
                addHeader(HttpHeaders.Accept, ContentType.Application.Json.toString())
                setBody(UPDATE_PASSENGER)
            }
        ) {
            Assertions.assertEquals(HttpStatusCode.NoContent, response.status())
        }
    }
}

private fun withBookingTestApplication(useCase: UseCase<UpdatePassengersData, BusinessError, Unit>): Application.() -> Unit {
    return withDefaultTestApplication {
        registerUpdatePassengersRoute(useCase, TestCalendar)
    }
}
a
Yes, it’s possible. Do you experience any specific problems?
j
I was able to make it works by using a custom applicatin.conf and setting the route that i wanted to test
Copy code
@Test
fun `can update passengers name 200 response`() = testApplication {
    environment {
        config = ApplicationConfig("application-test.conf")
    }
    application {
        installServerContentNegotiation()
        installIgnoreTrailingSlash()
        installKompendium()
        installRfcProblems()
        registerHealthRoutes()
        registerOASRoutes()
        registerUpdatePassengersRoute(
            object : UseCase<UpdatePassengersData, BusinessError, Unit> {
                override suspend fun invoke(command: Command<UpdatePassengersData>): Either<BusinessError, Unit> {
                    return Either.Right(Unit)
                }
            },
            TestCalendar
        )
    }

    val response = <http://client.post|client.post>("/updatePassengers") {
        header(HttpHeaders.ContentType, ContentType.Application.Json.toString())
        header(HttpHeaders.Accept, ContentType.Application.Json.toString())
        setBody(UPDATE_PASSENGER)
    }

    assertEquals(HttpStatusCode.NoContent, response.status)
    assertEquals("", response.bodyAsText())
}
and application-test.conf
Copy code
ktor {
    deployment {
        port = 8080
        runningLimit = 150
        tcpKeepAlive = false
        requestQueueLimit = 1500
        responseWriteTimeoutSeconds = 1
        connectionGroupSize = 2
        workerGroupSize =  8
        callGroupSize = 8
    }
/* Remove this block to avoid loading the main module
  application {
           modules = [ ApplicationKt.module ]
       }
*/
}
However, there is some base configuration that is necessary for every test, basically the one found in application section which installs content negotiation and other plugins. Also this module configures all the routes of my service.
Copy code
fun Application.module() {
    <http://logger.info|logger.info>("Starting main application...")

    installServerContentNegotiation()
    installIgnoreTrailingSlash()
    installKompendium()
    installRfcProblems()
    registerHealthRoutes()
    registerOASRoutes()
    //register all the routes of my service
      .....
   }
so in order to avoid loading all the routes for my tests and install the necessary plugins i had to copy and paste the plugin conf which i found not correct as it might not reflect the real configuration.
Copy code
environment {
        config = ApplicationConfig("application-test.conf")
    }
    application {
        installServerContentNegotiation()
        installIgnoreTrailingSlash()
        installKompendium()
        installRfcProblems()
        registerHealthRoutes()
        registerOASRoutes()
My question is , is it correct to test this way? i would like to load the main plugin configuration but choose which route to test so that i can mock individually.
Other problem i have is that if i want to simulate different scenarios i have to initialize the test app in every test and i am having problems with things being initialized twice as it seems that the test application is not destroyed after each test.