【发布时间】:2021-08-26 22:12:24
【问题描述】:
我有一个 Java Spring 启动项目,大量使用数据库 (Postgres) 作为它的存储库/数据。它是基本的 MVC 项目,控制器都是 REST 控制器。该项目运行良好(服务已启动,能够通过 REST 客户端调用服务等)。
现在,我正在向其中添加单元测试。我对 Spring Boot 很陌生,主要是单元测试部分。由于 CI/CD(构建管道),我无法使用持久/外部数据库进行测试。因此我需要使用内存数据库。
初始运行(主类)运行一堆数据库查询以在项目启动时建立缓存。所以我需要 postgres DB 进行测试(使用了很多 DB 函数)。
基本上,我需要使用 Testcontainers (postgresql)。我正在编写一个非常基本的测试来掌握它。
我存储了 schema.sql 和 data.sql(仅用于测试)。
src
|
main
test
|
resources
|
application-test.properties
schema.sql
data.sql
相关pom.xml
<properties>
<java.version>11</java.version>
<testcontainers.version>1.15.1</testcontainers.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20201115</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
我的测试课:
@Testcontainers
@Sql(scripts = {"file:src/test/resources/schema.sql","file:src/test/resources/data.sql"})
class ApplicationTests {
@Container
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:12")
.withUsername("testcontainers")
.withPassword("testcontainers")
.withDatabaseName("tescontainers");
@Test
void testPostgreSQLModule() throws SQLException {
try (Connection connection = DriverManager
.getConnection(postgreSQLContainer.getJdbcUrl(), "testcontainers", "testcontainers");
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM table_from_schema")) {
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
System.out.println(resultSet.getString("column1"));
}
}
}
}
}
我只是想测试数据库。
但是,当我运行测试时,它失败了
org.postgresql.util.PSQLException: ERROR: relation "table_from_schema" does not exist
我尝试调试它,即在我的测试 (testPostgreSQLModule) 中停止。我可以用 Postgres 看到 docker 组件。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc3ff1e04ceb postgres:12 "docker-entrypoint.s…" 16 seconds ago Up 15 seconds
但是当我登录并运行 psql 时,我看到数据库(测试容器)已创建,但它没有任何架构(表/函数)。
tescontainers=# \dt
Did not find any relations.
tescontainers=#
基本上,我的文件没有被运行。
在我的例子中,类级别的 @SQL 注释是否不适用于 Testcontainers 初始化?
这里需要什么来运行我的两个初始脚本?
我尝试使用 .withInitScript,它运行了。但是,我有很多数据要初始化并且文件太大(并且会增长),所以我将 DDL(模式)和插入(数据)分开。现在,我的问题是如何使用“withInitScript”运行多个初始化文件(schema.sql、data.sql)?所以我尝试了@SQL注解,但它似乎不起作用。
---更新/编辑----
为了明确上下文,我在下面寻找。谁能指导一下?
- 所有配置文件 (dev/ist/uat/prod) 都应使用各自的持久性数据库(来自其应用程序。env.properties)。
- 仅用于测试,我需要内存数据库,但不能使用 H2(和类似),因为我有很多与数据库相关的测试并且需要 Postgres(函数等)。所以,试试 Testcontainers。
- 当应用程序启动时,它会从各自的 DB(基于 env)中获取一些数据以准备初始缓存,并且其他方法将在为任何休息调用提供服务时使用它。因此,对于 Test (仅)我需要一个包含所有模式/数据(我可以通过 SQL 文件提供)的新内存数据库,以便在测试时启动应该使用该测试数据库并且相应的测试将基于该初始数据进行。
- 所以我需要一种方法来在测试运行时调出测试数据库(内存中/测试容器),并传递多个 SQL 文件以初始化测试数据库(在任何测试运行之前)。知道什么是最好的方法吗?
【问题讨论】:
标签: java postgresql spring-boot unit-testing testcontainers