Compartir comentarios
Las respuestas se generan en base a la documentación.

Escribir pruebas con Testcontainers

Antes de escribir las pruebas, crea un script SQL para sembrar datos de prueba en src/test/resources/test-data.sql:

DELETE FROM comments;
DELETE FROM posts;
DELETE FROM users;

INSERT INTO users(id, name, email) VALUES
(1, 'Siva', '[email protected]'),
(2, 'Oleg', '[email protected]');

INSERT INTO posts(id, title, content, created_by, created_at) VALUES
(1, 'Post 1 Title', 'Post 1 content', 1, CURRENT_TIMESTAMP),
(2, 'Post 2 Title', 'Post 2 content', 2, CURRENT_TIMESTAMP);

INSERT INTO comments(id, name, content, post_id, created_at) VALUES
(1, 'Ron', 'Comment 1', 1, CURRENT_TIMESTAMP),
(2, 'James', 'Comment 2', 1, CURRENT_TIMESTAMP),
(3, 'Robert', 'Comment 3', 2, CURRENT_TIMESTAMP);

Probar con el slice @JooqTest

La anotación @JooqTest carga únicamente los componentes de la capa de persistencia y autoconfigura el DSLContext de jOOQ. Utiliza la URL JDBC especial de Testcontainers para iniciar un contenedor de Postgres.

Crea UserRepositoryJooqTest.java:

package com.testcontainers.demo.domain;

import static org.assertj.core.api.Assertions.assertThat;

import org.jooq.DSLContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
import org.springframework.test.context.jdbc.Sql;

@JooqTest(
  properties = {
    "spring.test.database.replace=none",
    "spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db",
  }
)
@Sql("/test-data.sql")
class UserRepositoryJooqTest {

  @Autowired
  DSLContext dsl;

  UserRepository repository;

  @BeforeEach
  void setUp() {
    this.repository = new UserRepository(dsl);
  }

  @Test
  void shouldCreateUserSuccessfully() {
    User user = new User(null, "John", "[email protected]");

    User savedUser = repository.createUser(user);

    assertThat(savedUser.id()).isNotNull();
    assertThat(savedUser.name()).isEqualTo("John");
    assertThat(savedUser.email()).isEqualTo("[email protected]");
  }

  @Test
  void shouldGetUserByEmail() {
    User user = repository.getUserByEmail("[email protected]").orElseThrow();

    assertThat(user.id()).isEqualTo(1L);
    assertThat(user.name()).isEqualTo("Siva");
    assertThat(user.email()).isEqualTo("[email protected]");
  }
}

Esto es lo que hace la prueba:

  • @JooqTest carga solo la capa de persistencia y autoconfigura DSLContext.
  • La URL JDBC especial de Testcontainers (jdbc:tc:postgresql:16-alpine:///db) inicia automáticamente un contenedor de PostgreSQL.
  • Debido a que flyway-core está en el classpath, Spring Boot ejecuta las migraciones de Flyway desde src/main/resources/db/migration al iniciar.
  • @Sql("/test-data.sql") carga los datos de prueba antes de cada prueba.
  • Se instancia manualmente UserRepository con el DSLContext inyectado.

Prueba de integración con @SpringBootTest

Para una prueba de integración completa, utiliza @SpringBootTest con el soporte @ServiceConnection de Testcontainers introducido en Spring Boot 3.1.

Crea UserRepositoryTest.java:

package com.testcontainers.demo.domain;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.test.context.jdbc.Sql;
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@SpringBootTest
@Sql("/test-data.sql")
@Testcontainers
class UserRepositoryTest {

  @Container
  @ServiceConnection
  static PostgreSQLContainer postgres = new PostgreSQLContainer(
    "postgres:16-alpine"
  );

  @Autowired
  UserRepository repository;

  @Test
  void shouldCreateUserSuccessfully() {
    User user = new User(null, "John", "[email protected]");

    User savedUser = repository.createUser(user);

    assertThat(savedUser.id()).isNotNull();
    assertThat(savedUser.name()).isEqualTo("John");
    assertThat(savedUser.email()).isEqualTo("[email protected]");
  }

  @Test
  void shouldGetUserByEmail() {
    User user = repository.getUserByEmail("[email protected]").orElseThrow();

    assertThat(user.id()).isEqualTo(1L);
    assertThat(user.name()).isEqualTo("Siva");
    assertThat(user.email()).isEqualTo("[email protected]");
  }
}

Esto es lo que hace la prueba:

  • @SpringBootTest carga todo el contexto de la aplicación, por lo que UserRepository se inyecta directamente.
  • @Testcontainers y @Container gestionan el ciclo de vida del contenedor de PostgreSQL.
  • @ServiceConnection autoconfigura las propiedades del datasource a partir del contenedor en ejecución, eliminando la necesidad de usar @DynamicPropertySource.
  • @Sql("/test-data.sql") inicializa los datos de prueba.

Probar PostRepository

Prueba el PostRepository que recupera grafos de objetos complejos utilizando la URL JDBC especial de Testcontainers.

Crea PostRepositoryTest.java:

package com.testcontainers.demo.domain;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;

@SpringBootTest(
  properties = {
    "spring.test.database.replace=none",
    "spring.datasource.url=jdbc:tc:postgresql:16-alpine:///db",
  }
)
@Sql("/test-data.sql")
class PostRepositoryTest {

  @Autowired
  PostRepository repository;

  @Test
  void shouldGetPostById() {
    Post post = repository.getPostById(1L).orElseThrow();

    assertThat(post.id()).isEqualTo(1L);
    assertThat(post.title()).isEqualTo("Post 1 Title");
    assertThat(post.content()).isEqualTo("Post 1 content");
    assertThat(post.createdBy().id()).isEqualTo(1L);
    assertThat(post.createdBy().name()).isEqualTo("Siva");
    assertThat(post.createdBy().email()).isEqualTo("[email protected]");
    assertThat(post.comments()).hasSize(2);
  }
}

Esta prueba verifica que getPostById carga la publicación junto con su creador y comentarios en una sola consulta utilizando la característica MULTISET de jOOQ.