Piotr Pradzynski
Piotr Pradzynski

Reputation: 4535

How to avoid initializationError in kotest with SpringBootTest?

I have a simple JUnit "smoke" test which check if Spring context is loaded correctly:

@SpringBootTest
class ContextLoadJUnit {

    @Test
    fun contextLoads() {
        //empty by design
    }
}

I'm trying to rewrite it into kotest. I've tested two versions:

@SpringBootTest
@ApplyExtension(SpringTestExtension::class)
class ContextLoadKotestWordSpec : WordSpec({
  "context" should { "load with WordSpec" {} }
})

@SpringBootTest
class ContextLoadKotestFunSpec : FunSpec() {

    override fun extensions(): List<Extension> {
        return listOf(SpringExtension)
    }
    init {
        test("context should load with FunSpec") {}
    }
}

I have all three tests in one file:

import io.kotest.core.extensions.ApplyExtension
import io.kotest.core.extensions.Extension
import io.kotest.core.spec.style.FunSpec
import io.kotest.core.spec.style.WordSpec
import io.kotest.extensions.spring.SpringExtension
import io.kotest.extensions.spring.SpringTestExtension
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
class ContextLoadJUnit {

    @Test
    fun contextLoads() {
        //empty by design
    }
}

@SpringBootTest
@ApplyExtension(SpringTestExtension::class)
class ContextLoadKotestWordSpec : WordSpec({
  "context" should { "load with WordSpec" {} }
})

@SpringBootTest
class ContextLoadKotestFunSpec : FunSpec() {

    override fun extensions(): List<Extension> {
        return listOf(SpringExtension)
    }
    init {
        test("context should load with FunSpec") {}
    }
}

When they are running and passing, they are handled correctly:

3 tests are passing

But when they are failing, kotest are "wrapped" into initializationError and it looks like I have only two tests:

looks like 2 tests are failing (but I have 3)

Is there a way to prepare kotest somehow differently, avoid the initializationError and see that I have three separate failing tests?

Upvotes: 1

Views: 1046

Answers (1)

Karsten Gabriel
Karsten Gabriel

Reputation: 3662

Kotest's SpringExtension is an instance of SpringTestExtension which is a SpecExtension and a TestCaseExtension.

The initialization of the application context happens in the intercept function of the SpecExtension part of the extension. When the initialization of the application context fails, the spec has never been executed, and thus, the single tests of the spec have never been initialized. This has the effect that IntelliJ does not show any failed tests -- there simply are no failed tests, only a failed spec.

We can by-pass that behavior by taking only parts of the SpringExtension's initialization logic and put it in a test like this:

import io.kotest.core.spec.style.FunSpec
import org.springframework.test.context.TestContextManager

class KotestWithSpring : FunSpec() {
    init {
        val testContextManager = TestContextManager(this::class.java)
        test("context should load") {
            testContextManager.beforeTestClass()
            testContextManager.prepareTestInstance(this)
        }
    }
}

When the application context for this test class fails, it looks like this:

Screenshot of test execution result in IntelliJ

Upvotes: 2

Related Questions