or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-io-kotlintest--kotlintest-runner-junit5

JUnit Platform TestEngine implementation for KotlinTest framework, enabling KotlinTest specifications to run as JUnit 5 tests

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.kotlintest/kotlintest-runner-junit5@3.4.x

To install, run

npx @tessl/cli install tessl/maven-io-kotlintest--kotlintest-runner-junit5@3.4.0

index.mddocs/

KotlinTest Runner JUnit5

KotlinTest Runner JUnit5 is a JUnit Platform TestEngine implementation that integrates the KotlinTest testing framework with JUnit 5 ecosystem. It enables KotlinTest specifications to be discovered and executed by JUnit Platform launchers, allowing KotlinTest's expressive testing styles to work seamlessly with JUnit 5 tooling including IDEs, build tools like Gradle and Maven, and CI/CD systems.

Package Information

  • Package Name: kotlintest-runner-junit5
  • Package Type: maven
  • Language: Kotlin
  • Group ID: io.kotlintest
  • Artifact ID: kotlintest-runner-junit5
  • Installation: Add to build.gradle: testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.4.2'

Core Imports

import io.kotlintest.runner.junit5.KotlinTestEngine
import io.kotlintest.specs.*

For test specifications, extend from the spec classes:

import io.kotlintest.specs.StringSpec
import io.kotlintest.specs.FunSpec
import io.kotlintest.specs.BehaviorSpec
// ... other spec types

Basic Usage

// Example test using StringSpec with JUnit 5 integration
import io.kotlintest.specs.StringSpec
import io.kotlintest.shouldBe

class CalculatorTest : StringSpec({
    "addition should work correctly" {
        val result = 2 + 2
        result shouldBe 4
    }
    
    "multiplication should work correctly" {
        val result = 3 * 4
        result shouldBe 12
    }
})

The engine is automatically discovered by JUnit Platform through service loading, so no explicit configuration is needed beyond adding the dependency.

Architecture

The integration works through several key components:

  • TestEngine Implementation: KotlinTestEngine implements JUnit Platform's TestEngine interface
  • Test Discovery: Converts JUnit discovery requests to KotlinTest's internal format
  • Execution Bridging: Translates KotlinTest's test execution model to JUnit Platform's execution lifecycle
  • IDE Integration: IntelliJ-compatible spec classes for better development experience
  • Thread Safety: Synchronized execution listeners to handle concurrent test execution

Capabilities

Test Engine Implementation

Core JUnit Platform TestEngine that discovers and executes KotlinTest specifications.

class KotlinTestEngine : TestEngine {
    companion object {
        const val EngineId = "kotlintest"
    }
    
    override fun getId(): String
    override fun discover(
        request: EngineDiscoveryRequest,
        uniqueId: UniqueId
    ): KotlinTestEngineDescriptor
    override fun execute(request: ExecutionRequest)
    
    class KotlinTestEngineDescriptor(
        id: UniqueId,
        val classes: List<KClass<out Spec>>
    ) : EngineDescriptor {
        override fun mayRegisterTests(): Boolean
    }
}

Test Execution Listener

JUnit Platform execution listener that bridges KotlinTest's execution events to JUnit Platform's reporting model.

class JUnitTestRunnerListener(
    private val listener: EngineExecutionListener,
    val root: EngineDescriptor
) : TestEngineListener {
    
    data class ResultState(val testCase: TestCase, val result: TestResult)
    
    override fun engineStarted(classes: List<KClass<out Spec>>)
    override fun engineFinished(t: Throwable?)
    override fun beforeSpecClass(klass: KClass<out Spec>)
    override fun afterSpecClass(klass: KClass<out Spec>, t: Throwable?)
    override fun enterTestCase(testCase: TestCase)
    override fun invokingTestCase(testCase: TestCase, k: Int)
    override fun exitTestCase(testCase: TestCase, result: TestResult)
    override fun specInitialisationFailed(klass: KClass<out Spec>, t: Throwable)
}

Thread-Safe Execution Listener

Synchronized wrapper around EngineExecutionListener to handle concurrent test execution safely.

class SynchronizedEngineExecutionListener(
    val listener: EngineExecutionListener
) : EngineExecutionListener {
    
    override fun executionFinished(
        testDescriptor: TestDescriptor?,
        testExecutionResult: TestExecutionResult?
    )
    override fun reportingEntryPublished(
        testDescriptor: TestDescriptor?,
        entry: ReportEntry?
    )
    override fun executionSkipped(
        testDescriptor: TestDescriptor?,
        reason: String?
    )
    override fun executionStarted(testDescriptor: TestDescriptor?)
    override fun dynamicTestRegistered(testDescriptor: TestDescriptor?)
}

Discovery Request Conversion

Utility function that converts JUnit Platform discovery requests to KotlinTest's internal discovery format.

/**
 * Returns a KotlinTest [DiscoveryRequest] built from the selectors and filters present
 * in the JUnit [EngineDiscoveryRequest].
 *
 * Supported selectors are:
 * - [ClassSelector] - used to specify a single class by fully qualified name
 * - [DirectorySelector] - classes are scanned in the given directory
 * - [UriSelector] - classes are scanned from the given uri
 * - [PackageSelector] - classes are scanned on the default classpath for the given package name
 *
 * Support filters are:
 * - [ClassNameFilter] - filters out specs based on a classname
 * - [PackageNameFilter] - filters out specs based on package names
 *
 * Unsupported selectors are:
 * - [MethodSelector] - not supported because kotlintest does not define tests as methods/functions
 */
internal fun discoveryRequest(request: EngineDiscoveryRequest): DiscoveryRequest

IntelliJ IDE Integration Specs

Abstract spec classes that provide better IntelliJ IDEA integration through marker interface and annotations.

interface IntelliMarker {
    @EnabledIfSystemProperty(named = "wibble", matches = "wobble")
    @TestFactory
    fun primer() {
    }
}

abstract class AnnotationSpec(
    body: AbstractAnnotationSpec.() -> Unit = {}
) : AbstractAnnotationSpec(body), IntelliMarker

abstract class BehaviorSpec(
    body: AbstractBehaviorSpec.() -> Unit = {}
) : AbstractBehaviorSpec(body), IntelliMarker

abstract class DescribeSpec(
    body: AbstractDescribeSpec.() -> Unit = {}
) : AbstractDescribeSpec(body), IntelliMarker

abstract class ExpectSpec(
    body: AbstractExpectSpec.() -> Unit = {}
) : AbstractExpectSpec(body), IntelliMarker

abstract class FeatureSpec(
    body: AbstractFeatureSpec.() -> Unit = {}
) : AbstractFeatureSpec(body), IntelliMarker

abstract class FreeSpec(
    body: AbstractFreeSpec.() -> Unit = {}
) : AbstractFreeSpec(body), IntelliMarker

abstract class FunSpec(
    body: AbstractFunSpec.() -> Unit = {}
) : AbstractFunSpec(body), IntelliMarker

abstract class ShouldSpec(
    body: AbstractShouldSpec.() -> Unit = {}
) : AbstractShouldSpec(body), IntelliMarker {
    infix fun String.should(matcher: Matcher<String>): Unit
}

abstract class StringSpec(
    body: AbstractStringSpec.() -> Unit = {}
) : AbstractStringSpec(body), IntelliMarker

abstract class WordSpec(
    body: AbstractWordSpec.() -> Unit = {}
) : AbstractWordSpec(body), IntelliMarker {
    infix fun String?.should(matcher: Matcher<String?>): Unit
}

Debug Utilities

Extension functions for debugging JUnit Platform discovery requests.

fun EngineDiscoveryRequest.string(): String
fun LauncherDiscoveryRequest.string(): String

UniqueId Extensions

Extension function for creating spec-specific unique IDs in the JUnit Platform descriptor hierarchy.

fun UniqueId.appendSpec(description: Description): UniqueId

Types

// From KotlinTest framework (imported dependencies)
interface Spec
interface TestEngineListener
interface TestCase
interface TestResult
interface TestStatus
interface Description
class Matcher<T>

// From JUnit Platform (imported dependencies)  
interface TestEngine
interface EngineDiscoveryRequest
interface ExecutionRequest
interface TestDescriptor
interface EngineExecutionListener
interface TestExecutionResult
interface ReportEntry
class UniqueId
class EngineDescriptor

Service Registration

The engine is automatically registered with JUnit Platform through Java's ServiceLoader mechanism:

  • Service File: META-INF/services/org.junit.platform.engine.TestEngine
  • Implementation: io.kotlintest.runner.junit5.KotlinTestEngine

This allows JUnit Platform to automatically discover and use the KotlinTest engine without explicit configuration.

Error Handling

The engine handles various error scenarios:

  • Spec Initialization Failures: Reported as test failures in JUnit Platform
  • Test Execution Failures: Converted to JUnit Platform's TestExecutionResult format
  • Discovery Errors: Logged and result in empty test descriptor sets
  • Thread Safety: All listener notifications are synchronized to prevent race conditions

Integration Notes

  • Gradle Integration: Works with Gradle's JUnit Platform support
  • Maven Integration: Compatible with Maven Surefire plugin's JUnit Platform support
  • IDE Support: IntelliJ IDEA can discover and run KotlinTest specifications
  • CI/CD: Works with any CI/CD system that supports JUnit Platform
  • Filtering: Supports JUnit Platform's test filtering mechanisms (packages, classes, etc.)
  • Parallel Execution: Respects KotlinTest's parallelism configuration