How to run unit tests for teamcity BuildTypes created by Teamcity Kotlin DSL?

We are using Teamcity Kotlin DSL to create our buildings in TeamCity and writing some unit tests for the build types. In the build.gradle.kts , we have added the dependencies as followed:

dependencies {
    api("org.jetbrains.teamcity:configs-dsl-kotlin-latest:${teamcityDslVersion}")
    api("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT@pom") {
        isTransitive = true
    }
    api("org.jetbrains.kotlin:kotlin-stdlib")

    testImplementation("junit:junit:4.13.2")
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
    testImplementation("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT@pom")}
    .....
    SourceSets {
   test {
        kotlin.srcDirs("src/test")
    }
    }

But when we try to run a very simple test case in IntelliJ:

fun test_basic(){
        val a = BuildType { id("A") }
        val b = BuildType { id("B") }
}

It will raise the error as:

jetbrains/buildServer/configs/ConfigException
java.lang.NoClassDefFoundError: jetbrains/buildServer/configs/ConfigException
	at jetbrains.buildServer.configs.kotlin.IdsKt.createId(Ids.kt:90)
	at jetbrains.buildServer.configs.kotlin.IdsKt.access$createId(Ids.kt:1)
	at jetbrains.buildServer.configs.kotlin.EntityId.<init>(Ids.kt:74)
	at jetbrains.buildServer.configs.kotlin.BuildTypeSettings.<init>(BuildTypeSettings.kt:39)
	at jetbrains.buildServer.configs.kotlin.BuildType.<init>(BuildType.kt:88)
	at jetbrains.buildServer.configs.kotlin.BuildType.<init>(BuildType.kt:104)
	at testJarUnit.test_basic(testJarUnit.kt:24)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.......................
Caused by: java.lang.ClassNotFoundException: jetbrains.buildServer.configs.ConfigException
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:527)

Any advice? thanks

0
7 comments

Hi,

The NoClassDefFoundError you're encountering (specifically for jetbrains.buildServer.configs.ConfigException) typically means that some required TeamCity DSL runtime classes are missing from your test classpath.

Even though your code compiles correctly—thanks to the @pom dependency providing metadata—at test runtime, the actual .jar files containing the class implementations aren't available.

This happens because you're depending on configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT@pom, which only resolves the POM file, not the actual runtime .jars, unless they're explicitly declared or pulled in transitively.

You could try the following approach

- Remove @pom from the plugin dependency to ensure the actual .jar is included, not just the POM metadata.

- Use a concrete version for ${teamcityDslVersion} (e.g., 2025.03) instead of relying on snapshot behavior.

- Add the plugin jar to testImplementation as well, since your test code needs to instantiate actual TeamCity DSL classes at runtime.

dependencies {
    api("org.jetbrains.teamcity:configs-dsl-kotlin-latest:${teamcityDslVersion}")
    api("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT") { // Remove @pom
        isTransitive = true
    }
    // ... other dependencies

    testImplementation("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT") // Remove @pom here too
}

 

Best Regards,

Tom

0

Hi Tom, thanks for your kind reply. 

I have tried all above solutions, unfortunately it still raises same above errors. It seems in test run time, we could not access to any components in the teamcity:configs-dsl-kotlin. Although I could see the teamcity:config-dsl-kotlin-latest:2024.03 in the External Libraries in the project in IntelliJ

1. Remove the @pom

2. Use a concrete version (try 2024.03,  2024.12 etc)

And my build.gradle.kts is like as followed now

dependencies {
    api("org.jetbrains.teamcity:configs-dsl-kotlin-latest:2024.03")
    api("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT") {
        isTransitive = true
    }
    api("org.jetbrains.kotlin:kotlin-stdlib")

    // test dependency for later use
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.5.31") // For Kotlin testing
    testImplementation("org.jetbrains.teamcity:configs-dsl-kotlin-latest:2024.03")

    // Add the TeamCity Kotlin DSL dependency
    testImplementation("org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest:1.0-SNAPSHOT")
}

How could we add the teamcity:config-dsl-kotlin-latest jar to testimplementation? Based on you mentioned above

 Add the plugin jar to testImplementation as well, since your test code needs to instantiate actual TeamCity DSL classes at runtime.

Thanks

0

Furthermore, if I add one more test case like:

object project: Project({
    id("project")
    name="projectName"})
 @Test
 fun test_basic2(){
    println (project.name)}

It will raise the validation error, I think it is still missing the components of teamcity:config-dsl-kotlin

> Task :test
........org.junit.platform.launcher.core.EngineDiscoveryOrchestrator lambda$logTestDescriptorExclusionReasons$7
INFO: 0 containers and 1 tests were Method or class mismatch

jetbrains/buildServer/configs/ValidationException
java.lang.NoClassDefFoundError: jetbrains/buildServer/configs/ValidationException
	at jetbrains.buildServer.configs.kotlin.IdsKt.createId(Ids.kt:90)
	at jetbrains.buildServer.configs.kotlin.IdsKt.access$createId(Ids.kt:1)
	at jetbrains.buildServer.configs.kotlin.EntityId.<init>(Ids.kt:74)
	at jetbrains.buildServer.configs.kotlin.Project.<init>(Project.kt:114)
	at jetbrains.buildServer.configs.kotlin.Project.<init>(Project.kt:220)
	at project.<init>(testJarUnit.kt:16)
	at project.<clinit>(testJarUnit.kt)
	at testJarUnit.test_basic(testJarUnit.kt:38)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	..........................................
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: java.lang.ClassNotFoundException: jetbrains.buildServer.configs.ValidationException
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:527)
	... 91 more
0

Hi,

I test it with following dependencies. It works correctly on my side. 

val teamcityDslVersion = "2025.03"
dependencies {
    implementation("org.jetbrains.teamcity:server-api:$teamcityDslVersion")
    implementation("org.jetbrains.teamcity:configs-dsl-kotlin:$teamcityDslVersion")
    testImplementation(kotlin("test"))
    testImplementation("org.jetbrains.kotlin:kotlin-test") // provides `assertEquals`
....
}

For more detailed information, please refer to the screenshot.

Best Regards,

Tom

0

Hi Tom,

Yeah.. it works now.  Thanks for your kind help.

I think the key is the line

implementation("org.jetbrains.teamcity:server-api:$teamcityDslVersion")

This module is for Creating TeamCity server-side plugins , why is it related to the test running? Is it used to access TeamCity server infrastructure?

Thanks

fzhurd

0

Hi,

Thanks for your response. Yes, you are right — this dependency is intended for developing TeamCity server-side plugins. From what I understand, it seems that internally references some server-side classes in its implementation. Even if your test code only directly uses BuildType, the JVM may still attempt to load all related classes at runtime. If the necessary classes are missing from the runtime classpath, the JVM will throw a NoClassDefFoundError or ClassNotFoundException.

Best Regards,
Tom

0

It makes sense. Thanks for your kind help and explanation. 

Regards

fzhurd

0

Please sign in to leave a comment.