Search code examples
ktorspekkotlintest

Ktor: testing REST endpoints using Spek/KotlinTest instad of JUnit Test Class


I have a simple hello world Ktor app:

fun Application.testMe() {
  intercept(ApplicationCallPipeline.Call) {
    if (call.request.uri == "/")
      call.respondText("Hello")
    }
}

With JUnit test class I can write the test for it, as given in its documentation; as following:

class ApplicationTest {
    @Test fun testRequest() = withTestApplication(Application::testMe) {
        with(handleRequest(HttpMethod.Get, "/")) {
            assertEquals(HttpStatusCode.OK, response.status())
            assertEquals("Hello", response.content)
        }
        with(handleRequest(HttpMethod.Get, "/index.html")) {
            assertFalse(requestHandled)
        }
    }
}

However, I want to do a unit test in Spek or KotlinTest, without the help of JUnit, similar to the way I do it in ScalaTest/Play; in a more declarative way:

  1. Send a FakeRequest to the route (i.e., /) during a test.
  2. Get the content of the page, and check for the string "hello".

The question is can I write the above test in a more declarative way in KotlinTest or Spek?


Solution

  • First of all, follow spek setup guide with JUnit 5

    Then you can simply declare you specifications like the following

    object HelloApplicationSpec: Spek({
        given("an application") {
            val engine = TestApplicationEngine(createTestEnvironment())
            engine.start(wait = false) // for now we can't eliminate it
            engine.application.main() // our main module function
    
            with(engine) {
                on("index") {
                    it("should return Hello World") {
                        handleRequest(HttpMethod.Get, "/").let { call ->
                            assertEquals("Hello, World!", call.response.content)
                        }
                    }
                    it("should return 404 on POST") {
                        handleRequest(HttpMethod.Post, "/", {
                            body = "HTTP post body"
                        }).let { call ->
                            assertFalse(call.requestHandled)
                        }
                    }
                }
            }
        }
    })
    

    Here is my build.gradle (simplified)

    buildscript {
        dependencies {
            classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3'
        }
    
        repositories {
            jcenter()
        }
    }
    
    repositories {
        jcenter()
        maven { url "http://dl.bintray.com/jetbrains/spek" }
    }
    
    apply plugin: 'org.junit.platform.gradle.plugin'
    
    junitPlatform {
        filters {
            engines {
                include 'spek'
            }
        }
    }
    
    dependencies {
        testCompile 'org.jetbrains.spek:spek-api:1.1.5'
        testRuntime 'org.jetbrains.spek:spek-junit-platform-engine:1.1.5'
        testCompile "io.ktor:ktor-server-test-host:$ktor_version"
    }