【问题标题】:Embedded PostgreSQL for Java JUnit tests嵌入式 PostgreSQL for Java JUnit 测试
【发布时间】:2012-12-28 03:39:00
【问题描述】:

是否有嵌入式 PostgreSql 以便我们可以对 PostgreSql 驱动的应用程序进行单元测试?

由于 PostgreSql 有一些方言,所以最好使用嵌入式 PostgreSql 本身而不是其他嵌入式数据库。

Embedded 并不一定意味着它必须嵌入到 JVM 进程中。它也不一定需要使用内存中的持久性。它应该由依赖管理(Maven、Gradle)自动加载,以便单元测试可以在每台机器上运行,而无需安装和配置本地 PostgreSQL 服务器。

【问题讨论】:

    标签: postgresql maven junit embedded-database database-driven


    【解决方案1】:

    这是一个“嵌入式”PostgresSQL 服务器,专为从 Java 进行单元测试而设计:

    https://github.com/yandex-qatools/postgresql-embedded

    嵌入式 postgresql 将为在单元测试中运行 postgres 二进制文件提供一种平台中立的方式。大部分代码都是从Flapdoodle OSS's embed process

    顺便说一句,MongoRedisMemcachednodejs 也存在类似的项目。

    【讨论】:

    • 为什么没有标记为正确答案?这个库有缺点吗?它具有 postgre 的所有功能吗?可以用模块等装饰吗?
    • 我可以证明它运作良好。标准 Postgres。用法示例:github.com/icgc-dcc/dcc-submission/blob/develop/…github.com/icgc-dcc/dcc-submission/blob/…
    • “嵌入”的含义实际上还不清楚,但对我来说,它就像 H2 一样在内存中运行。而 yandex-qatools/postgresql-embedded 不符合这个定义。实际上它会下载指定的 postgres 版本,将其解压缩到临时目录并启动服务器,所有这些都会导致磁盘开销,这在非企业环境中是难以接受的。我正在判断这个示例项目github.com/scottmf/postgresql-integration-test,它仍然是一个很好的例子。如果我错了,请纠正我
    • 我团队的一些成员实施了github.com/opentable/otj-pg-embedded,它似乎为他们提供了很好的服务。使用 Spring 配置时,它具有更清晰的界面。
    • 如果您尝试在默认配置之外使用此解决方案(从其他地方下载包等),此解决方案会出现问题
    【解决方案2】:

    不,在进程内可加载数据库即库的意义上,没有嵌入式 PostgreSQL。 PostgreSQL 是面向进程的;每个后端都有一个线程,它会产生多个进程来完成工作。作为图书馆,它没有意义。

    The H2 database支持a limited subset of the PostgreSQL SQL dialect和PgJDBC驱动的使用。

    可以做的是initdb a new temporary database,在随机端口上用pg_ctl启动它,这样它就不会与其他实例冲突,运行你的测试,然后用pg_ctl停止最后删除临时数据库。

    强烈建议您在非默认端口上运行临时 postgres, 这样您就不会冒险与运行测试的机器上任何本地安装的 PostgreSQL 发生冲突.

    (is "在ecpg 的意义上嵌入了 PostgreSQL,本质上是一个 PostgreSQL client 嵌入在 C source code 中作为基于预处理器C 语言扩展。它仍然需要一个正在运行的服务器,而且使用起来有点讨厌,不太推荐。它的存在主要是为了使从其他各种数据库的移植更容易。)

    【讨论】:

    • 我也会这样做。在没有任何安装程序的情况下设置 Postgres 的批处理文件/shell 脚本大约需要 5 行代码。尽管在每个单元测试运行中执行 initdb 可能会太慢。
    • @a_horse_with_no_name 是的,如果在构建过程中丢失了 initdb,您可以随时解压缩预 initdb 的数据库或从干净的​​模板中复制。不过升级 Pg 时会很痛苦。就我个人而言,我发现 initdb 足够快,但我不再使用旋转磁盘了。至于批处理文件 - 主要挑战是确保您使用非冲突端口(特别是在运行并发测试时)并确保在完成后终止服务器。特别是在 Windows 上,在服务器停止之前您无法删除数据目录。
    • 您说“将面向过程的部分打包为库没有意义”。为什么不?现在,您可以使用 Java 库自动化 IE。当然,进程将在幕后产生,但您仍然可以轻松地与 Java 库交谈来实现它。 PostgreSQL 应该也是如此。你可以通过嵌入一个 PostgreSQL 安装程序来接近这个目标,但是有很多样板只是为了设置它。
    • PostgreSQL 是否可以即时启动,无论它之前是否已安装在机器上?也许这就是 OP 所需要的。我知道这就是我需要的。我不希望我的单元测试依赖于预安装的 PostgreSQL,因为这意味着依赖于不同团队中进程的正确运行,特别是维护 TeamCity 代理的团队。另外,我希望新的过程方法允许完整的服务器配置,这在预先存在的安装中通常是困难的(可能作为 root)。
    • @MihaiDanila 绝对是,这就是我的建议。只需捆绑 Pg 二进制文件的 .zip,然后按需使用 pg_ctl 启动 Pg。您可以在initdbinitdb 参数之后编辑配置,通过环境变量或参数控制端口等内容到pg_ctl 等。
    【解决方案3】:

    我尝试了@btiernay (yandex-qatools) 建议的项目。我花了好几天的时间,没有任何冒犯,这是过度设计的解决方案,在我的情况下不起作用,因为我想从内部存储库下载二进制文件而不是去公共互联网。理论上它支持它,但实际上它不支持。

    OpenTable 嵌入式 PostgreSQL 组件

    我最终使用了otj-pg-embedded,它就像一个魅力。在 cmets 中提到过,所以我想我也会在这里提一下。

    我将它用作独立数据库,而不是通过规则用于单元测试和本地开发。

    依赖关系:

    <dependency>
        <groupId>com.opentable.components</groupId>
        <artifactId>otj-pg-embedded</artifactId>
        <version>0.7.1</version>
    </dependency>
    

    代码:

    @Bean
    public DataSource dataSource(PgBinaryResolver pgBinaryResolver) throws IOException {
        EmbeddedPostgres pg = EmbeddedPostgres.builder()
            .setPgBinaryResolver(pgBinaryResolver)
            .start();
    
    
        // It doesn't not matter which databse it will be after all. We just use the default.
        return pg.getPostgresDatabase();
    }
    
    @Bean
    public PgBinaryResolver nexusPgBinaryResolver() {
        return (system, machineHardware) -> {
            String url = getArtifactUrl(postgrePackage, system + SEPARATOR + machineHardware);
            log.info("Will download embedded Postgre package from: {}", url);
    
            return new URL(url).openConnection().getInputStream();
        };
    }
    
    private static String getArtifactUrl(PostgrePackage postgrePackage, String classifier) {
        // Your internal repo URL logic
    }
    

    【讨论】:

    • 是否可以从otj-pg-embedded 中的.sql 文件创建架构。我没有使用弹簧。没有Rule,我没有找到任何示例。
    • 多年来一直使用 otj-pg-embedded 并取得了巨大的成功。像魅力一样工作
    【解决方案4】:

    您可以使用 PostgreSQL 的 container 实例。

    由于旋转容器只需几秒钟,这对于单元测试应该足够了。 此外,如果您需要持久化数据,例如为了调查,您不需要保存整个容器,只需要保存数据文件,这些文件可以映射到容器之外。

    可以在here 找到如何执行此操作的示例之一。

    【讨论】:

      【解决方案5】:

      如果您希望从集成(或类似)测试套件运行 postgres 的进程内版本,postgresql-embedded 对我来说很好。

      我写了一个small maven plugin,它可以用作一个maven 包装器,它围绕一个postgresql-embedded 的分叉版本。

      【讨论】:

      • 再次提醒,如果您超出默认配置,此解决方案会出现问题
      • 很公平。但是,在 maven 插件中,我专门添加了一个配置选项,用于将二进制文件的下载 URL 设置为默认位置以外的位置。
      • 请查看github.com/aramcodz/embedded-postgres-maven-plugin并查找“downloadUrl”插件配置参数。
      • 你试过了吗?因为底层库有bug。没有插件可以解决这个问题 - 库本身有错误。尝试清除 postgre 二进制文件的本地缓存,在与 Internet 断开连接时从本地 url (file:///...) 下载。我敢打赌它不会启动(至少它对我来说失败了,我将它调试到我清楚地看到一个忽略传递给 initDb 命令的任何设置的错误)
      • @JanZyka,是的,我刚试了一下,发现从本地下载成功了。我清理了二进制文件的本地缓存(移动到另一个本地文件夹(远离 ~/.embedpostgresql),并在 maven 配置中使用了 file:////my_local_folder/dev/tmp/ 的 downloadUrl。这是一个 sn-p输出:'Download Version{9.2.4-1}:OS_X:B64 START Download Version{9.2.4-1}:OS_X:B64 DownloadSize: 64139929 Download Version{9.2.4-1}:OS_X:B64 0% 1%...94% 95% 96% 97% 98% 99% 100% 下载版本{9.2.4-1}:OS_X:B64 以 62636kb/s 下载 下载版本{9.2.4-1}:OS_X:B64完成'
      【解决方案6】:

      我在测试中使用 PostgreSQL 的 container 实例。 https://www.testcontainers.org/#about https://www.testcontainers.org/modules/databases/jdbc/

      依赖:

              <dependency>
                  <groupId>org.junit.jupiter</groupId>
                  <artifactId>junit-jupiter-api</artifactId>
                  <version>5.7.2</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.junit.jupiter</groupId>
                  <artifactId>junit-jupiter-params</artifactId>
                  <version>5.7.2</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.junit.jupiter</groupId>
                  <artifactId>junit-jupiter-engine</artifactId>
                  <version>5.7.2</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.testcontainers</groupId>
                  <artifactId>testcontainers</artifactId>
                  <version>1.15.3</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.testcontainers</groupId>
                  <artifactId>junit-jupiter</artifactId>
                  <version>1.15.3</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.testcontainers</groupId>
                  <artifactId>postgresql</artifactId>
                  <version>1.15.3</version>
                  <scope>test</scope>
              </dependency>
      

      然后做测试:

      @SpringBootTest
      @ActiveProfiles({"test"})
      @Testcontainers
      class ApplicationTest {
          @Container
          static PostgreSQLContainer<?> postgreSQL = new PostgreSQLContainer<>("postgres:12.7");
      
          @DynamicPropertySource
          static void postgreSQLProperties(DynamicPropertyRegistry registry) {
              registry.add("spring.datasource.username", postgreSQL::getUsername);
              registry.add("spring.datasource.password", postgreSQL::getPassword);
          }
      
      
          @Test
          void someTests() {
      
          }
      

      在 application-test.yml 中:

      source:
        datasource:
          url: jdbc:tc:postgresql:12.7:///databasename
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-27
        • 2018-04-29
        • 1970-01-01
        • 2011-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多