Skip to content

Testing Ktor applications

Sergey edited this page Nov 2, 2023 · 3 revisions

In brief

The hs-test library allows you to test projects using the Ktor framework.

Setup Ktor template

It's strongly recommended to use the following template and just add to it additional dependencies. If you need other things in your build.gradle for the app, please contact Hyperskill.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-serialization:$hs.kotlin.version"
    }
}

apply plugin: 'java'
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'kotlinx-serialization'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}
sourceSets.main.resources.srcDirs = ["src/resources"]

dependencies {
    implementation "io.ktor:ktor-server-core-jvm:$hs.ktor.version"
    implementation "io.ktor:ktor-server-netty-jvm:$hs.ktor.version"
    implementation "ch.qos.logback:logback-classic:1.4.8"

    implementation "io.ktor:ktor-server-content-negotiation:$hs.ktor.version"
    implementation "io.ktor:ktor-serialization-kotlinx-json:$hs.ktor.version"
    implementation "io.ktor:ktor-serialization-gson:$hs.ktor.version"
    implementation "io.ktor:ktor-serialization-jackson:$hs.ktor.version"


    testImplementation "io.ktor:ktor-server-tests-jvm:$hs.ktor.version"
    testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$hs.kotlin.version"

    implementation "org.jetbrains.kotlin:kotlin-stdlib"
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0"
    testImplementation "io.ktor:ktor-server-test-host:$hs.ktor.version"
}

And build.gradle for the project.

buildscript {
    apply plugin: 'hyperskill'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$hs.kotlin.version"
    }
}

subprojects {
    apply plugin: 'application'
    apply plugin: 'java'
    apply plugin: 'kotlin'
    apply plugin: 'hyperskill'

    def userJava = Integer.parseInt(JavaVersion.current().getMajorVersion())
    def hsJava = Integer.parseInt("$hs.kotlin.javaVersion")
    def testJava = Math.max(userJava, hsJava)

    java.toolchain.languageVersion = JavaLanguageVersion.of(testJava)

    compileJava {
        javaCompiler = javaToolchains.compilerFor {
            languageVersion = JavaLanguageVersion.of(userJava)
        }
    }

    compileTestJava {
        javaCompiler = javaToolchains.compilerFor {
            languageVersion = JavaLanguageVersion.of(testJava)
        }
    }

    repositories {
        mavenCentral()
        maven { url 'https://packages.jetbrains.team/maven/p/hyperskill-hs-test/maven' }
        maven { url 'https://jitpack.io' }
    }

    dependencies {
        testImplementation 'com.github.hyperskill:hs-test:release-SNAPSHOT'
    }

    configurations.all {
        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
    }

    sourceSets {
        main.java.srcDir 'src'
        test.java.srcDir 'test'
    }

    test {
        systemProperty "file.encoding", "utf-8"
        outputs.upToDateWhen { false }
    }

    compileJava.options.encoding = 'utf-8'
    tasks.withType(JavaCompile) {
        options.encoding = 'utf-8'
    }
}

project(':util') {
    dependencies {
        implementation 'com.github.hyperskill:hs-test:release-SNAPSHOT'
    }
}

configure(subprojects.findAll {it.name != 'util'}) {
    dependencies {
        testImplementation project(':util').sourceSets.main.output
        testImplementation project(':util').sourceSets.test.output
    }
}

wrapper {
    gradleVersion = hs.gradle.version
}

settings.gradle

buildscript {
  repositories {
    maven { url 'https://packages.jetbrains.team/maven/p/hyperskill-hs-test/maven' }
    maven { url 'https://jitpack.io' }
  }

  dependencies {
    classpath "com.github.hyperskill:hs-gradle-plugin:release-SNAPSHOT"

  }

  configurations.all {
    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
  }
}

static String sanitizeName(String name) {
  return name.replaceAll("[ /\\\\:<>\"?*|()]", "_").replaceAll("(^[.]+)|([.]+\$)", "")
}

rootProject.projectDir.eachDirRecurse {
  if (!isTaskDir(it) || it.path.contains(".idea")) {
    return
  }
  def taskRelativePath = rootDir.toPath().relativize(it.toPath())
  def parts = []
  for (name in taskRelativePath) {
    parts.add(sanitizeName(name.toString()))
  }
  def moduleName =  parts.join("-")
  include "$moduleName"
  project(":$moduleName").projectDir = it
}

def isTaskDir(File dir) {
  return new File(dir, "src").exists() || new File(dir, "test").exists()
}

include 'util'

The project downloads all the necessary versions from the plugin hs-gradle-plugin.

Attention!!! When writing tests, in order to avoid unexpected error when performing tests, we recommend wrapping the testApplication call into a try-catch construct.

class Test : StageTest<Any>()  {

    @DynamicTest
    fun test1() : CheckResult {
        var result: CheckResult = CheckResult.correct()
        try {
            testApplication {
                // some code
            }
        } catch (e: Exception) {
            result = CheckResult.wrong(e.message)
        }
        return result
    }
}