0

We have a Spring Boot project written in kotlin (for the first time) where we want to try kotlintest for writing tests.

Our datasource is a postgresql database, and in our tests we utilize org.testcontainers:postgresql in order to not use a separate datasource like h2, or having to use a test schema in our actual database. Since firing up a testcontainer is a somewhat lengthy operation, we want it to only be done once across multiple tests.

We use liquibase to evolve the database schema.

So with that in mind we created an abstract class ContainerDatabaseTest which other tests can extend from:

class KPostgresContainer(imageName: String) : PostgreSQLContainer<KPostgresContainer>(imageName)

@ContextConfiguration(initializers = [ContainerDatabaseTest.Initializer::class])
abstract class ContainerDatabaseTest {
    companion object {
        val container: KPostgresContainer = KPostgresContainer("postgres:9.6.15")
                .withDatabaseName("ic_orders_testcontainer_test")
                .withUsername("ic_orders")
                .withPassword("ic_orders")

        init {
            container.start()
        }
    }

    class Initializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
        override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) {
            val values = TestPropertyValues.of(
                    "spring.datasource.url=${container.jdbcUrl}",
                    "spring.datasource.username=${container.username}",
                    "spring.datasource.password=${container.password}",
                    "spring.liquibase.user=${container.username}",
                    "spring.liquibase.password=${container.password}"
            )
            values.applyTo(configurableApplicationContext)
        }
    }
}

This fires up a testcontainer, once across all the tests that extend it during the test run.

This is then used e.g. like this using JUnit5

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class RepositoriesTests @Autowired constructor(
        val em: TestEntityManager,
        val moveOrderPlacementRepository: MoveOrderPlacementRepository
) : ContainerDatabaseTest() {

    @Test
    fun `Persist an object to database`() {
        em.persist(someObject)

But how can I rewrite these tests to kotlintest? In kotlintest you extend from a Spec (abstract class as well), and in kotlin you cannot extend from multiple classes as far as I understand.

So how would I go about porting this test to kotlintest? I thought about beforeAll or afterAll in ProjectConfig, but I don't want or need a testcontainer for all tests, only those that requires a datasource. Then there is the TestListener concept described in the reference, but I struggle to rewrite to that as well.

Any pointers? Thanks!

Terje Andersen
  • 429
  • 2
  • 17

1 Answers1

1

The problem here is TestContainers. Currently the @TestContainers annotation will not be inherited (there is an open issue redarding that and seems to be fixed within the next release). as workaround you can annotate the parent class as well as the test class with @TestContainers until it's fixed.

to use with junit5 you will need org.testcontainers:junit-jupiter dependency as well the testcontainers dependency itself. the jupiter one will add junit5 extensions to your project.

as far as I know kotlintest is using junit5 as testrunner? so it should work as well.

EDIT: This has been fixed now. Thereby you only need to annotate the Parent class with @TestContainers