Kotlin, JUnit5, JDBC

I needed to test some Kotlin code that used JDBC. I wanted an embedded SQL database for my JUnit5 tests. I’ve done this in Java a number of times so I dug into my old code and … nothing was a fit. The issues were they were very Java centric and JUnit4 based. Here’s what I rolled on my own.

JDBC Compatible Database

H2 provided an easy solution to that:

 Class.forName("org.h2.Driver")
 val connection = DriverManager.getConnection(
    "jdbc:h2:mem:test", 
    "sa",
    ""
)!!

Kotlin and JUnit5

For Kotlin and JUnit5 I know from experience I wanted to go with implementing an @ExtendWith annotation. I also wanted test classes to have easy access to the resultant connection. Here’s what I did for that:

import org.junit.jupiter.api.extension.ExtendWith
import java.sql.Connection

@ExtendWith(EmbeddedDb::class)
open class WithConnection {
    lateinit var connection: Connection
}

This allowed tests to look like:

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class SomeTest : WithConnection() {
    @Test
    fun `should have a valid connection`() {
        assertThat(connection).isNotNull
    }
}

The meat of the work happens in the EmbeddedDb class:

import org.junit.jupiter.api.extension.AfterEachCallback
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext
import java.sql.DriverManager

class EmbeddedDb : BeforeEachCallback, AfterEachCallback {
    override fun beforeEach(context: ExtensionContext) {
        Class.forName("org.h2.Driver")
        val connection = DriverManager.getConnection(
           "jdbc:h2:mem:test", 
           "sa",
           ""
        )!!
        (context.requiredTestInstance as WithConnection)
           .connection = connection
    }
    override fun afterEach(context: ExtensionContext) {
        (context.requiredTestInstance as WithConnection)
           .connection.close()
    }
}

It’s very light weight, all it’s doing is instantiating a connection, and setting the one used by the test classes.

What You Get

With this approach, you’ll get a fresh database connection for every test method, and the connection will be set already if you add a @BeforeEach to your test class, so you can set up your schema there.