https://kotlinlang.org logo
#spring
Title
# spring
m

Maciej Nawrocki

03/06/2024, 4:40 PM
Hi all 👋, I want to share with you an article, where I explain how to integrate Testcontainers with spring in an elegant way: https://brightinventions.pl/blog/spring-tests-with-testcontainers/ Let me know what you think about it 👍
🙌 1
r

Raimund Klein

03/06/2024, 4:59 PM
Hi Maciej. It’s an interesting approach to solving an issue that is now more or less obsolete thanks to the
@ServiceConnection
annotation: https://www.baeldung.com/spring-boot-built-in-testcontainers#using-serviceconnection-for-dynamic-properties
👀 1
👍 1
t

thanksforallthefish

03/08/2024, 7:57 AM
it's also really a problem that depends on the test framework used. we use #kotest that has a better lifecycle than junit and in there you can an extension (a project extension in the case of testcontainers) so that the containers are started before the whole spring stuff even starts. then setting 2 system variable overriding some spring property and it's done:
Copy code
class ProjectConfig : AbstractProjectConfig() {
  override fun extensions() = listOf(
    ClearMockkExtension,
    LocalstackExtension,
    PostgresExtension,
    KafkaExtension,
    SpringExtension,
    SpringAutowireConstructorExtension,
  )
)

object PostgresExtension : ProjectExtension {
  private val delegate = lazy {
    PostgreSQLContainerProvider().newInstance("14.4")
      .withNetwork(Network.SHARED)
      .withNetworkAliases("db")
  }
  private val withNetworkAliases by delegate

  override suspend fun interceptProject(context: ProjectContext, callback: suspend (ProjectContext) -> Unit) {
    beforeProject()
    callback(context)
    afterProject()
  }

  private fun beforeProject() {
    if (!withEnvVariables()) {
      withNetworkAliases.start()
      System.setProperty("spring.datasource.url", "jdbc:postgresql://${withNetworkAliases.connectionString()}")
      System.setProperty("spring.datasource.username", withNetworkAliases.username)
      System.setProperty("spring.datasource.password", withNetworkAliases.password)
      System.setProperty("spring.flyway.schemas", withNetworkAliases.databaseName)
    } else {
      System.setProperty(
        "spring.datasource.url",
        "jdbc:postgresql://${System.getenv("POSTGRES_HOST")}:5432/${System.getenv("POSTGRES_DB")}"
      )
      System.setProperty("spring.datasource.username", System.getenv("POSTGRES_USER"))
      System.setProperty("spring.datasource.password", System.getenv("POSTGRES_PASSWORD"))
      System.setProperty("spring.flyway.schemas", System.getenv("POSTGRES_DB"))
    }
  }

  private fun afterProject() {
    if (delegate.isInitialized()) withNetworkAliases.stop()
  }

  private fun withEnvVariables() = System.getenv("POSTGRES_DB").isNotBlank()

  private fun JdbcDatabaseContainer<*>.connectionString() = "$host:$firstMappedPort/$databaseName"
}