如何在 Quarkus 中以编程方式覆盖应用程序 属性
how to override an application property programatically in Quarkus
我最近开始使用 testcontantainers 在我的 Quarkus 网络应用程序中 unit/integration 测试数据库操作。它工作正常,除了我想不出在 quarkus.datasource.url
应用程序 属性 中动态设置 MySQL 端口的方法。目前我正在使用已弃用的 withPortBindings
方法强制容器将暴露的 MySQL 端口绑定到端口 11111 但正确的方法是让测试容器选择一个随机一个并覆盖 quarkus.datasource.url
属性.
我的单元测试class
@Testcontainers
@QuarkusTest
public class UserServiceTest {
@Container
private static final MySQLContainer MY_SQL_CONTAINER = (MySQLContainer) new MySQLContainer()
.withDatabaseName("userServiceDb")
.withUsername("foo")
.withPassword("bar")
.withUrlParam("serverTimezone", "UTC")
.withExposedPorts(3306)
.withCreateContainerCmdModifier(cmd ->
((CreateContainerCmd) cmd).withHostName("localhost")
.withPortBindings(new PortBinding(Ports.Binding.bindPort(11111), new ExposedPort(3306))) // deprecated, let testcontainers pick random free port
);
@BeforeAll
public static void setup() {
// TODO: use the return value from MY_SQL_CONTAINER.getJdbcUrl()
// to set %test.quarkus.datasource.url
LOGGER.info(" ********************** jdbc url = {}", MY_SQL_CONTAINER.getJdbcUrl());
}
// snip...
}
我的application.properties:
%test.quarkus.datasource.url=jdbc:mysql://localhost:11111/userServiceDb?serverTimezone=UTC
%test.quarkus.datasource.driver=com.mysql.cj.jdbc.Driver
%test.quarkus.datasource.username=foo
%test.quarkus.datasource.password=bar
%test.quarkus.hibernate-orm.dialect=org.hibernate.dialect.MySQL8Dialect
Quarkus guide to configuring an app描述了如何以编程方式读取应用程序属性:
String databaseName = ConfigProvider.getConfig().getValue("database.name", String.class);
但不知道如何设置。 This tutorial 关于将测试容器与 Quarkus 结合使用暗示它应该是可能的:
// 不应使用以下 - 函数已弃用,为了测试简单,您应该在运行时覆盖您的属性
解决方案:
正如接受的答案中所建议的,我不必在数据源 属性 中指定主机和端口。所以解决办法就是简单的把application.properties:
中的两行替换掉
%test.quarkus.datasource.url=jdbc:mysql://localhost:11111/userServiceDb
%test.quarkus.datasource.driver=com.mysql.cj.jdbc.Driver
和
%test.quarkus.datasource.url=jdbc:tc:mysql:///userServiceDb
%test.quarkus.datasource.driver=org.testcontainers.jdbc.ContainerDatabaseDriver
(并删除不必要的 withExposedPorts
和 withCreateContainerCmdModifier
方法调用)
请仔细阅读文档。端口可以省略。
现在(quarkus版本19.03.12)可以简单一点
- 定义启动容器并覆盖 JDBC props
的测试组件
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.testcontainers.containers.PostgreSQLContainer;
public class PostgresDatabaseResource implements QuarkusTestResourceLifecycleManager {
public static final PostgreSQLContainer<?> DATABASE = new PostgreSQLContainer<>("postgres:10.5")
.withDatabaseName("test_db")
.withUsername("test_user")
.withPassword("test_password")
.withExposedPorts(5432);
@Override
public Map<String, String> start() {
DATABASE.start();
return Map.of(
"quarkus.datasource.jdbc.url", DATABASE.getJdbcUrl(),
"quarkus.datasource.db-kind", "postgresql",
"quarkus.datasource.username", DATABASE.getUsername(),
"quarkus.datasource.password", DATABASE.getPassword());
}
@Override
public void stop() {
DATABASE.stop();
}
}
- 在测试中使用它
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import javax.ws.rs.core.MediaType;
import java.util.UUID;
import java.util.stream.Collectors;
import static io.restassured.RestAssured.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@QuarkusTest
@QuarkusTestResource(PostgresDatabaseResource.class)
public class MyControllerTest {
@Test
public void myAwesomeControllerTestWithDb() {
// whatever you want to test here. Quarkus will use Container DB
given().contentType(MediaType.APPLICATION_JSON).body(blaBla)
.when().post("/create-some-stuff").then()
.statusCode(200).and()
.extract()
.body()
.as(YourBean.class);
}
我最近开始使用 testcontantainers 在我的 Quarkus 网络应用程序中 unit/integration 测试数据库操作。它工作正常,除了我想不出在 quarkus.datasource.url
应用程序 属性 中动态设置 MySQL 端口的方法。目前我正在使用已弃用的 withPortBindings
方法强制容器将暴露的 MySQL 端口绑定到端口 11111 但正确的方法是让测试容器选择一个随机一个并覆盖 quarkus.datasource.url
属性.
我的单元测试class
@Testcontainers
@QuarkusTest
public class UserServiceTest {
@Container
private static final MySQLContainer MY_SQL_CONTAINER = (MySQLContainer) new MySQLContainer()
.withDatabaseName("userServiceDb")
.withUsername("foo")
.withPassword("bar")
.withUrlParam("serverTimezone", "UTC")
.withExposedPorts(3306)
.withCreateContainerCmdModifier(cmd ->
((CreateContainerCmd) cmd).withHostName("localhost")
.withPortBindings(new PortBinding(Ports.Binding.bindPort(11111), new ExposedPort(3306))) // deprecated, let testcontainers pick random free port
);
@BeforeAll
public static void setup() {
// TODO: use the return value from MY_SQL_CONTAINER.getJdbcUrl()
// to set %test.quarkus.datasource.url
LOGGER.info(" ********************** jdbc url = {}", MY_SQL_CONTAINER.getJdbcUrl());
}
// snip...
}
我的application.properties:
%test.quarkus.datasource.url=jdbc:mysql://localhost:11111/userServiceDb?serverTimezone=UTC
%test.quarkus.datasource.driver=com.mysql.cj.jdbc.Driver
%test.quarkus.datasource.username=foo
%test.quarkus.datasource.password=bar
%test.quarkus.hibernate-orm.dialect=org.hibernate.dialect.MySQL8Dialect
Quarkus guide to configuring an app描述了如何以编程方式读取应用程序属性:
String databaseName = ConfigProvider.getConfig().getValue("database.name", String.class);
但不知道如何设置。 This tutorial 关于将测试容器与 Quarkus 结合使用暗示它应该是可能的:
// 不应使用以下 - 函数已弃用,为了测试简单,您应该在运行时覆盖您的属性
解决方案: 正如接受的答案中所建议的,我不必在数据源 属性 中指定主机和端口。所以解决办法就是简单的把application.properties:
中的两行替换掉%test.quarkus.datasource.url=jdbc:mysql://localhost:11111/userServiceDb
%test.quarkus.datasource.driver=com.mysql.cj.jdbc.Driver
和
%test.quarkus.datasource.url=jdbc:tc:mysql:///userServiceDb
%test.quarkus.datasource.driver=org.testcontainers.jdbc.ContainerDatabaseDriver
(并删除不必要的 withExposedPorts
和 withCreateContainerCmdModifier
方法调用)
请仔细阅读文档。端口可以省略。
现在(quarkus版本19.03.12)可以简单一点
- 定义启动容器并覆盖 JDBC props 的测试组件
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.testcontainers.containers.PostgreSQLContainer;
public class PostgresDatabaseResource implements QuarkusTestResourceLifecycleManager {
public static final PostgreSQLContainer<?> DATABASE = new PostgreSQLContainer<>("postgres:10.5")
.withDatabaseName("test_db")
.withUsername("test_user")
.withPassword("test_password")
.withExposedPorts(5432);
@Override
public Map<String, String> start() {
DATABASE.start();
return Map.of(
"quarkus.datasource.jdbc.url", DATABASE.getJdbcUrl(),
"quarkus.datasource.db-kind", "postgresql",
"quarkus.datasource.username", DATABASE.getUsername(),
"quarkus.datasource.password", DATABASE.getPassword());
}
@Override
public void stop() {
DATABASE.stop();
}
}
- 在测试中使用它
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import javax.ws.rs.core.MediaType;
import java.util.UUID;
import java.util.stream.Collectors;
import static io.restassured.RestAssured.given;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@QuarkusTest
@QuarkusTestResource(PostgresDatabaseResource.class)
public class MyControllerTest {
@Test
public void myAwesomeControllerTestWithDb() {
// whatever you want to test here. Quarkus will use Container DB
given().contentType(MediaType.APPLICATION_JSON).body(blaBla)
.when().post("/create-some-stuff").then()
.statusCode(200).and()
.extract()
.body()
.as(YourBean.class);
}