TestContainers Kotlin SpringBoot

TestContainers Kotlin SpringBoot

Olá pessoal dessa vez mostro de forma resumida como configurar TestContainers com Kotlin e SpringBoot.

Cenário

Em um projeto SpringBoot é bem comum configurarmos o banco H2 com o intuito de usá-lo como banco de dados de testes, porém nem sempre essa abordagem é eficaz. Quando precisamos ter uma alta fidelidade com o banco de produção ou usar-mos alguma funcionalidade inerente do mesmo, como “functions” por exemplo, a escolha do H2 deixa a desejar. Para esses casos específicos uma escolha válida seria fazer uso do TestContainers.

O que é o TestContainers?

É uma biblioteca Java que suporta testes JUnit, fornecendo instâncias leves e descartáveis ​​de bancos de dados comuns, navegadores Selenium ou qualquer outra coisa que possa ser executada em um contêiner Docker.

Pré-Requisito para Uso

Ter o Docker instalado na sua máquina.

Contras

Será em média mais lento do que o H2.

Contexto do Exemplo

  • Será um projeto em Kotlin + SpringBoot + PostgreSQL + TestContainers
  • Será um exemplo curto e direto ao ponto.
  • O domínio se trata de uma lojinhas de pasteis, onde só o contexto dos nomes dos pasteis será abordado.

Início

Crie o projeto no Spring Initializr (Linguagem: Kotlin. Spring Boot: 3.2.5. Java: 17)

Abra o projeto no Intellij (ou no editor de sua preferencia 😌). 

Confirme se as dependências no arquivo “build.gradle” estão conforme abaixo:


dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  implementation 'org.jetbrains.kotlin:kotlin-reflect'
  runtimeOnly 'org.postgresql:postgresql'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
  testImplementation 'org.springframework.boot:spring-boot-testcontainers'
  testImplementation 'org.testcontainers:junit-jupiter'
  testImplementation 'org.testcontainers:postgresql'
}

Dentro da pasta do projeto, no meu caso “com.example.testcontainers”, crie uma data class Pastel conforme abaixo:

package com.example.testcontainers

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id

@Entity(name = "pasteis")
data class Pastel(
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Int = 0,
  @Column
  val name: String = ""
)
Agora crie uma interface chamada PastelRepository:
package com.example.testcontainers

import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface PastelRepository: JpaRepository<Pastel, Int> {}

Dentro da pasta “resources” renomeie o arquivo application.properties para application.yml(aqui é só frescura mesmo 🙃) e adicione o conteúdo abaixo:

spring:
  application:
    name: testcontainers
  datasource:
    url: jdbc:postgresql://${postgres.url}/${postgres.database}
    username: ${postgres.username}
    password: ${postgres.password}
    driver-class-name: org.postgresql.Driver
Agora ainda dentro da pasta resources crie um arquivo chamado: application-test.yml com o conteúdo abaixo:
postgres:
  url: localhost:${postgres.port}
  username: postgres
  password: postgres
  database: tes-cont-db
spring:
  jpa:
    hibernate:
      ddl-auto: create-drop
      show-sql: true
Na pasta de testes, use a classe de teste que já foi criada pelo Spring Initializr (eu renomeei ele para apenas “ApplicationTests”) e substitua seu conteúdo pelo conteúdo abaixo:

package com.example.testcontainers

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.FilterType
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.PostgreSQLContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import java.lang.annotation.Inherited

@SpringBootTest
@Testcontainers
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class ApplicationTests {

  @Autowired
  lateinit var pastelRegistry: PastelRepository

  companion object {
    @Container
    val db = PostgreSQLContainer<Nothing>("postgres:latest").apply {
      this.withDatabaseName("tes-cont-db")
      this.withUsername("postgres")
      this.withPassword("postgres")
    }

    @JvmStatic
    @DynamicPropertySource
    fun setDatasourceProperties(registry: DynamicPropertyRegistry) {
      registry.add(
      "postgres.port"
      ) { db.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT) }
    }
  }

  @Test
  fun contextLoads() {
    val pastel = Pastel(name = "Carne")
    pastelRegistry.save(pastel)
    val pasteis = pastelRegistry.findAll()
    Assertions.assertTrue(pasteis.isNotEmpty())
    Assertions.assertEquals(pastel.name, pasteis[0].name)
  }
}

É praticamente tudo o que você precisa para realizar um teste simples usando TestContainers

Agora é só executar o teste e ver a mágica acontecer 

Conclusão

O uso do TestContainers pode ser de grande ajuda para quando temos queries complexas ou usamos outras características particulares do banco de dados. Com isso garantimos similaridade entre o banco de produção e o de testes. Dessa forma podemos evitar falsos positivos/negativos devido a diferenças de cada banco.


Visite nosso canal no Youtube deixe seu comentário, sua inscrição e joinha.

Outra Leitura que pode te interessar: 3 Livros Que Todo Dev Precisa Ler

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima