Required dependencies: io.ktor:ktor-server-test-host
, org.jetbrains.kotlin:kotlin-test
Ktor provides a special testing engine that doesn't create a web server, doesn't bind to sockets, and doesn't make any real HTTP requests. Instead, it hooks directly into internal mechanisms and processes an application call directly. This results in quicker tests execution compared to running a complete web server for testing.
To test a server Ktor application, you need to include the following artifacts in the build script:
-
Add the
ktor-server-test-host
dependency: -
Add the
kotlin-test
dependency providing a set of utility functions for performing assertions in tests:
To use a testing engine, follow the steps below:
- Create a JUnit test class and a test function.
- Use the
testApplication
function to set up a configured instance of a test application running locally. - Use the Ktor HTTP client instance inside a test application to make a request to your server, receive a response, and make assertions.
The code below demonstrates how to test the most simple Ktor application that accepts GET requests made to the /
path and responds with a plain text response.
{src="snippets/engine-main/src/test/kotlin/EngineMainTest.kt" lines="3-16,27"}
{src="snippets/engine-main/src/main/kotlin/com/example/Application.kt" lines="3-15"}
The runnable code example is available here: engine-main.
To test an application, its modules should be loaded to testApplication
.
Loading modules to testApplication
depends on the way used to create a server: by using the application.conf
configuration file or in code using the embeddedServer
function.
If you have the application.conf
file in the resources
folder, testApplication
loads all modules and properties specified in the configuration file automatically.
You can disable loading modules by customizing an environment for tests.
If you use embeddedServer
, you can add modules to a test application manually using the application
function:
{src="snippets/embedded-server-modules/src/test/kotlin/EmbeddedServerTest.kt" lines="11-15,19"}
You can add routes to your test application using the routing
function.
This might be convenient for the following use-cases:
-
Instead of adding modules to a test application, you can add specific routes that should be tested.
-
You can add routes required only in a test application. The example below shows how to add the
/login-test
endpoint used to initialize a user session in tests:{src="snippets/auth-oauth-google/src/test/kotlin/ApplicationTest.kt" lines="18,31-35,51"}
You can find the full example with a test here: auth-oauth-google.
To build a custom environment for a test application, use the environment
function.
For example, to use a custom configuration for tests, you can create a custom configuration file in the test/resources
folder and load it using the config
property:
{src="snippets/auth-oauth-google/src/test/kotlin/ApplicationTest.kt" lines="17-21,51"}
Another way to specify configuration properties is using MapApplicationConfig. This might be useful if you want to access application configuration before the application starts. The example below shows how to pass MapApplicationConfig
to the testApplication
function using the config
property:
@Test
fun testRequest() = testApplication {
environment {
config = MapApplicationConfig("ktor.environment" to "test")
}
// Request and assertions
}
Ktor allows you to mock external services using the externalServices
function.
Inside this function, you need to call the hosts
function that accepts two parameters:
- The
hosts
parameter accepts URLs of external services. - The
block
parameter allows you to configure theApplication
that acts as a mock for an external service. You can configure routing and install plugins for thisApplication
.
The sample below shows how to use externalServices
to simulate a JSON response returned by Google API:
{src="snippets/auth-oauth-google/src/test/kotlin/ApplicationTest.kt" lines="18,36-47,51"}
You can find the full example with a test here: auth-oauth-google.
The testApplication
provides access to an HTTP client with default configuration using the client
property.
If you need to customize the client and install additional plugins, you can use the createClient
function. For example, to send JSON data in a test POST/PUT request, you can install the ContentNegotiation plugin:
{src="snippets/json-kotlinx/src/test/kotlin/ApplicationTest.kt" lines="32-37,44"}
To test your application, you can use a configured client to make a request and receive a response. The example below shows how to test the /customer
endpoint that handles POST
requests:
{src="snippets/json-kotlinx/src/test/kotlin/ApplicationTest.kt" lines="32-41,44"}
After receiving a response, you can verify the results by making assertions provided by the kotlin.test library:
{src="snippets/json-kotlinx/src/test/kotlin/ApplicationTest.kt" lines="32-44"}
To send form data in a test POST/PUT request, you need to set the Content-Type
header and specify the request body. To do this, you can use
the header and setBody functions, respectively. The examples below show how to send form data using both x-www-form-urlencoded
and multipart/form-data
types.
A test below from the post-form-parameters example shows how to make a test request with form parameters sent using the x-www-form-urlencoded
content type. Note that the formUrlEncode function is used to encode form parameters from a list of key/value pairs.
{src="snippets/post-form-parameters/src/test/kotlin/ApplicationTest.kt" lines="3-18,29"}
{src="snippets/post-form-parameters/src/main/kotlin/com/example/Application.kt" lines="3-16,45-46"}
The code below demonstrates how to build multipart/form-data
and test file uploading. You can find the full example here: upload-file.
{src="snippets/upload-file/src/test/kotlin/UploadFileTest.kt" lines="3-34,62"}
{src="snippets/upload-file/src/main/kotlin/com/example/UploadFile.kt" lines="3-34"}
To send JSON data in a test POST/PUT request, you need create a new client and install the ContentNegotiation plugin that allows serializing/deserializing the content in a specific format. Inside a request, you can specify the Content-Type
header using the contentType
function and the request body using setBody. The example below shows how to test the /customer
endpoint that handles POST
requests.
{src="snippets/json-kotlinx/src/test/kotlin/ApplicationTest.kt" lines="3-14,31-44,56"}
{src="snippets/json-kotlinx/src/main/kotlin/com/example/Application.kt" lines="3-16,25-31,38-44"}
If you need to preserve cookies between requests when testing, you need create a new client and install the HttpCookies plugin. In a test below from the session-cookie-client example, reload count is increased after each request since cookies are preserved.
{src="snippets/session-cookie-client/src/test/kotlin/ApplicationTest.kt" lines="3-27,47"}
{src="snippets/session-cookie-client/src/main/kotlin/com/example/Application.kt" lines="3-38"}
If you need to test an HTTPS endpoint, change the protocol used to make a request using the URLBuilder.protocol property:
{src="snippets/ssl-engine-main/src/test/kotlin/ApplicationTest.kt" lines="10-18"}
You can find the full example here: ssl-engine-main.
You can test WebSocket conversations by using the WebSockets plugin provided by the client:
{src="snippets/server-websockets/src/test/kotlin/com/example/ModuleTest.kt" lines="3-26,41"}
Apart from a testing engine, you can use the Ktor HTTP Client for end-to-end testing of your server application.
{src="snippets/embedded-server/src/test/kotlin/EmbeddedServerTest.kt"}
For a full example, refer to a test of the embedded-server example.