Testing Servers
Ktor provides some support for testing your server applications in an efficient way. It hooks tests directly into the framework’s routing mechanism, avoiding the need to run the underlying server and make network calls to it. This allows the tests to run a lot faster.
Task 4.4
-
Download
ktor-testing.zipfrom the Topic 2 folder in Minerva and unzip it in your SoCS Linux filestore or on your own PC. -
Examine the contents of the directory that is created. This is a Gradle project for a simple ‘Hello World’ Ktor application. Take a look at the
build.gradle.ktsfile. Notice the addition of three testing dependencies:testImplementation("io.ktor:ktor-server-test-host") testImplementation("io.kotest:kotest-assertions-core:5.9.1") testImplementation("io.kotest:kotest-runner-junit5:5.9.1")You’ve seen the two Kotest dependencies before. The other dependency extends Ktor with the testing support that we need.
-
Run the application with
./gradlew runVisiting
http://0.0.0.0:7070should give you a “Hello World!” message in the browser window.Try visiting
http://0.0.0.0:7070/hello/Kotlinand you should see a “Hello Kotlin!” message instead. -
Now run the tests:
./gradlew testA single test should run, and it should pass.
-
Locate the file
ApplicationTest.ktand examine it. Here’s the code for the single test:"Path / yields 'Hello World!' greeting" { testApplication { application { module() } val response = client.get("/") response.status shouldBe HttpStatusCode.OK response.headers["Content-Type"]?.shouldContain("text/plain") response.bodyAsText() shouldBe "Hello World!" } }This is similar to the Kotest examples you’ve seen earlier, but there are some important differences.
-
The body of the test is contained in a lambda expression which is passed to the
testApplication()function. -
The first thing in this lambda expression is some code to configure the application, invoking its top-level
module()function. (Remember that this, in turn, may invoke other modules, such asconfigureRouting().) -
The second thing in the lambda expression is some code to make a request. A GET request can be made by invoking the
get()extension function of a special object namedclient. A POST request can be made by invoking thepost()function. The request returns a response, and we can make assertions about the content of this response. -
The assertions have a form that should now be familiar to you. In this example, you can see how we can check three features of the HTTP response: the status code, the
Content-Typeheader, and the body.-
Notice how we use the object
HttpStatusCode.OKto represent a status of200 OK. There are constants like this defined for all other HTTP status codes. -
Notice the use of the safe call operator when checking for the
Content-Typeheader. This is becauseresponse.headersstores headers in a map, and looking up values in a map can returnnull. -
The body of the response needs to be converted explicitly into a string before we can check it, which is achieved using the
bodyAsText()extension function.
-
-
-
The application has two routes, but only one of them is currently tested. Add the missing test to
ApplicationTest.kt. Rerun the tests and make sure that both pass. -
Add a third test to check that a request for
http://0.0.0.0:7070/helloproduces a404 Not Foundresponse.
Further Reading
For more on how to test your applications, see the Testing in Ktor Server page in the official Ktor documentation.
The approach outlined above is suitable for testing only the request-handling code of a Ktor server. If you want to test all layers of software running on the server side, you could use Ktor to create a separate client application that makes a network request to a running server. This application could then make assertions about the response that it receives.
For full end-to-end testing of web applications in a browser, you should investigate tools like Playwright. This may come in handy for your project in Semester 2.