Categories
Development Tech

Better syntax highlighting in Intellij IDEA

Free code on a MacBook

Quick tip if you’re using Intellij IDEA and not every framework is supported: Add the annotations dependency.

This enables IDEA to get information about certain things in your code and apply the correct validation, information and/or formatting.

We only use it for one thing so far: Marking strings as SQL. That enables IDEA to recognize it and apply the correct highlighting.

The below example shows a wrapper method we have for JDBI, and because of the @Language annotation IDEA knows that it should apply SQL syntax highlighting.

fun createQuery(@Language("sql") sql: String): Query
Kotlin

Dependency:

implementation("org.jetbrains:annotations:24.0.0")
Kotlin

Try it out! 🙂


Subscribe for more 🙂

Categories
Development

JUnit and ParameterResolver — Caching database connections in your tests

This is a re-post of an original Medium article. As I am moving my content here I will re-post some content.


Car speeding on the road

We aim for fast tests, ideally completing all tests within 30 seconds. Currently, our tests take 1 minute and 30 seconds, but we are determined to to get ther. 😃 To achieve this goal, we must reduce the overhead of each run.

Read on to learn about the techniques we use to speed up DB connection handling and migrations.


We aim to minimize the number of database tests we write by using fakes, but we still require some tests to verify our DB layer. We just don’t want the majority of our tests slowed with network access (even locally in Docker).

Establishing connections takes time, and the overhead of checking migrations before each test can also be time-consuming. We usually run a persistent DB in a Docker container, so we only have to create connections and migrate once for each run. We do use Test Containers if no DB is available, but it is slower. Every millisecond counts. 😃

Therefore we looked for a way to minimize this when running thousands of tests.

JUnit enforces strict isolation between tests so you can’t just inherit a class or something and get a shared value across the run. But as we knew Spring caches contexts across tests, there had to be a way. JUnit ParameterResolvers come to the rescue:

class DatabaseTestExtension : ParameterResolver {
private val STORE_NAME = "main-database"
override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext?): Boolean {
return parameterContext.parameter.type == Database::class.java
}
override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any {
// We do the store thing here to avoid loading and migrating the DB for each test/class
// Will however load per thread, so are not guaranteed to be done only once
val store = extensionContext.root.getStore(Namespace.create(DatabaseTestExtension::class.java.simpleName))
val db: Database = (store.get(STORE_NAME) as Database?) ?: Database(Config.load()).also {
// New object so do initialization and store
it.initializeAndMigrate()
store.put(STORE_NAME, it)
}
return db
}
}

The Database and Config objects are just custom wrappers around HikariJDBI and Liquibase. You can store the JDBI object or a Hikari connection pool directly by changing the code above and adjustinng the class type. The important part is putting it in the store so it is persisted across runs.

To use it you do something like this:

@Test
@ExtendWith(DatabaseTestExtension::class)
fun testSomething(db: Database) {
}

Pro tip: You can add the ExtendWith annotation to the entire test class, not just the test method.

And just like that you have a resource that won’t take extra time/load to run when running all your tests. 😃


Subscribe for further updates 🙂