如何在初始化脚本中正确维护测试容器的数据?

问题描述

我正在使用 Testcontainers 加载一个 Dockerized 数据库,用于我的 Spring Boot 应用程序进行集成测试。我目前使用初始化脚本加载所有数据:

CREATE TABLE public.table1 (
...
...
);

CREATE TABLE public.table2 (
...
...
);

这一切正常。我也有自己的手动测试数据,我可以插入这些数据来测试不同的场景:

-- Data for pre-existing quiz
INSERT INTO public.table1 (id,prop1,prop2) values (1,'a','b');
INSERT INTO public.table2 (id,'c','d');
INSERT INTO public.table2 (id,prop2) values (2,'e','f');

同样,这一切正常,我正在使用 YAML 文件来读取模拟这些对象以用于我的测试

  table1s:
    first:
      id: 1
      prop1: a
      prop2: b
  table2s:
    first:
      id: 1
      prop1: c
      prop2: d
    second:
      id: 2
      prop1: e
      prop2: f

在其中我将能够将这些放入一个我可以从 YAML 文件属性中读取的类中,以便它可以用于我的测试类

public class Table1TestData {

    @Autowired
    private Environment env;

    private UUID id;
    private boolean prop1;
    private boolean prop2;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    public boolean getProp1() {
        return prop1;
    }

    public void setProp1(String trial) {
        this.prop1 = prop1;
    }

    ....

    public Table1TestData getFirstRowData(){
        Table1HelperFactory ret = new Table1HelperFactory();
        ret.setId(UUID.fromString(env.getProperty("table1s.first.id")));
        ret.setProp1(env.getProperty("table1s.first.id"));
        ....
        return ret;
    }
    ....

}

并且我在我的测试中使用这个助手作为自动装配的实体(特别是对于我的服务类):

public class Table1ServiceTest {

  @ClassRule
  public static PostgresContainer postgresContainer = PostgresContainer.getInstance();


  @Autowired
  Table1Service table1Service;

  @Autowired
  Table1TestData table1TestData;

  @Autowired
  mockmvc mockmvc;

  @Autowired
  ObjectMapper objectMapper;

  @BeforeAll
  private static void startup() {
    postgresContainer.start();
  }


  @Test
  @displayName("Table 1 Service Test")
  @Transactional
  public void findTable1ById() throws Exception {
    Table1TestData testData = table1TestData.getFirstRowData();
    Table1 table1 = table1Service.findTable1ById(testData.getId());
    assertNotNull(table1);
    assertEquals(table1.getId(),testData.getId());
    assertEquals(table1.prop1(),testData.prop1());
    ....

  }

}

但是,假设我必须将一个新列应用于 Table1(或任何真正的表),并且我将新架构放入 init 脚本中。我现在必须手动转到这些插入语句中的每一个并放入一个带有值的新列(假设没有认值),或者甚至说是否删除了列(即使它不一定影响类)。这最终变得很麻烦。

所以我的问题是,对于使用 init 脚本为容器化数据库填充测试数据的人来说,在没有太多手动管理的情况下有效维护这些数据的最佳方法是什么?

解决方法

我认为您可以利用 postgresql 的初始化脚本功能:只需将您的 sql 脚本放在 /docker-entrypoint-initdb.d 下(必要时创建目录),它会直接执行它们,无需任何编程工作。

您可以在此处查看示例: https://github.com/gmunozfe/clustered-ejb-timers-kie-server/blob/master/src/test/java/org/kie/samples/integration/ClusteredEJBTimerSystemTest.java

定义指向该目录的 postgresql:

.withFileSystemBind("etc/postgresql","/docker-entrypoint-initdb.d",BindMode.READ_ONLY)

如果您希望每个测试使用不同的脚本,请查看这篇文章: https://www.baeldung.com/spring-boot-data-sql-and-schema-sql