Search code examples
springspring-bootmavenkotlinkotest

Kotlin+Maven+Spring Boot+Kotest: Unable to initialize main class io.kotest.launcher.LauncherKt


I'm trying to run a simple unit test written with Kotest on a spring boot project. But unfortunately I get an error message

Testing started at 17:38 ...
Error: Unable to initialize main class io.kotest.launcher.LauncherKt
Caused by: java.lang.NoClassDefFoundError: io/kotest/core/engine/TestEngineListener

Process finished with exit code 1

My pom.xml file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-kotest-test</artifactId>
    <groupId>org.example</groupId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>consoleApp</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <kotlin.code.style>official</kotlin.code.style>
        <kotlin.compiler.jvmTarget>17</kotlin.compiler.jvmTarget>
        <kotlin.version>1.7.10</kotlin.version>

    </properties>

    <repositories>
        <repository>
            <id>mavenCentral</id>
            <url>https://repo1.maven.org/maven2/</url>
        </repository>
    </repositories>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <testSourceDirectory>src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>1.7.10</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>MainKt</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.7.3</version>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>${kotlin.version}</version>
        </dependency>


        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>${kotlin.version}</version>
        </dependency>

        <dependency>
            <groupId>io.kotest</groupId>
            <artifactId>kotest-runner-junit5</artifactId>
            <version>5.4.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.kotest.extensions</groupId>
            <artifactId>kotest-extensions-spring</artifactId>
            <version>1.1.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.kotest</groupId>
            <artifactId>kotest-assertions-core-jvm</artifactId>
            <version>5.4.2</version>
            <scope>test</scope>
        </dependency>


    </dependencies>

</project>

Simple example of spring boot project

package org.example.spring.kotest.test

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.stereotype.Service

@SpringBootApplication
open class SpringKotestTestApplication

@Service
class SomeService {
    fun foo() = 1
}

fun main(args: Array<String>) {
    runApplication<SpringKotestTestApplication>(*args)
}

My unit test:

package org.example.spring.kotest.test

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.extensions.spring.SpringExtension
import io.kotest.matchers.shouldBe
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
@EnableAutoConfiguration
class SomeServiceTest(
    private val someService: SomeService
) : DescribeSpec() {

    override fun extensions() = listOf(SpringExtension)

    init {
        describe("test") {
            it("test") {
                someService.foo().shouldBe(1)
            }
        }
    }
}

I've been trying to solve the problem for a very long time. It seems that Kotest works better with Gradle than with Maven :(


Solution

  • I don't think that Maven is to blame, but the problem is probably that there is some dependency wrong or missing.

    The TestEngineListener mentioned in the error message is contained in the artifact kotest-framework-engine-jvm which is transitively included, when you add kotest-runner-junit5-jvm to your project.

    So, I guess you just have to replace kotest-runner-junit5 in your pom with kotest-runner-junit5-jvm.