Tmfwang
Tmfwang

Reputation: 664

How do I start the application only once when testing in Ktor, instead of once per test?

I've been trying to write some tests for my Ktor application, and have followed the docs here:

https://ktor.io/docs/testing.html#end-to-end

...and using a test setup like this:

import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.testing.*
import kotlin.test.*

class ApplicationTest {
    @Test
    fun testRoot() = testApplication {
        val response = client.get("/")
        assertEquals(HttpStatusCode.OK, response.status)
        assertEquals("Hello, world!", response.bodyAsText())
    }
}

The problem is that when using testApplication in every test, is that the tests crashes when I have around 220 tests that should be run, because my application reads a json-file for every boot - resulting in a "too many open files" error.

What I want to do is run the application once, then send all my HTTP-requests to this single instance of the application, and then close the application.

What is instead happening above is that the application is booted and closed for each one of the over 200 tests, resulting in memory errors.

How do I run the application only once?

Upvotes: 4

Views: 1312

Answers (1)

Tmfwang
Tmfwang

Reputation: 664

Solved it!

We can start the application in a beforeAll function, instead of starting it in every test. Here's an example of how to do that:

import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.testing.*
import io.ktor.test.dispatcher.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test

class MyApiTest {
    lateinit var JSON: Json

    @Test
    fun `Test some endpoint`() = testSuspend {
        testApp.client.get("/something").apply {
            val actual = JSON.decodeFromString<SomeType>(bodyAsText())

            assertEquals(expected, actual)
        }
    }

    companion object {
        lateinit var testApp: TestApplication

        @JvmStatic
        @BeforeAll
        fun setup()  {
            testApp = TestApplication {  }          
        }

        @JvmStatic
        @AfterAll
        fun teardown() {
            testApp.stop()
        }
    }
}

Upvotes: 5

Related Questions