如何在 Quarkus 中以编程方式覆盖应用程序属性

3

我最近开始在我的Quarkus Web应用程序中使用testcontainers来进行单元/集成测试数据库操作。它可以很好地工作,但是我无法弄清楚如何在quarkus.datasource.url的应用程序属性中动态设置MySQL端口。目前,我正在使用已弃用的withPortBindings方法,强制容器将公开的MySQL端口绑定到端口11111,但正确的方法是让testcontainers选择一个随机的端口并覆盖quarkus.datasource.url属性。

我的单元测试类

    @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 应用配置指南 介绍了如何以编程方式读取应用程序属性:

String databaseName = ConfigProvider.getConfig().getValue("database.name", String.class);

但并没有说明如何设置。使用测试容器和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 方法调用)
2个回答

3

谢谢,你是正确的!我更新了我的问题,提供了适用于我的情况的具体解决方案。 - kosmičák

2

现在(quarkus版本19.03.12),它可以更简单一些。

  1. 定义测试组件,启动容器并覆盖JDBC属性。

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();
    }
}
  1. 在测试中使用它
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);
      
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接