【问题标题】:Is there a way to run MySQL in-memory for JUnit test cases?有没有办法为 JUnit 测试用例在内存中运行 MySQL?
【发布时间】:2011-10-07 17:51:39
【问题描述】:

我只是想为访问 MySQL 数据库的服务添加测试用例,我想重新创建整个架构(在某些情况下,也只需使用 MySQL 转储文件,其中包含每个测试用例所需的数据)。我环顾四周,发现一些人使用 SQLite / H2 和其他人来执行此操作,但我只是在徘徊,是否有任何方法可以在内存中运行 MySQL,所以我不需要担心 MySQL 特有的任何事情我可能会在我们的服务中使用方言。

【问题讨论】:

    标签: java mysql junit


    【解决方案1】:

    这是使用专有 SQL 扩展通常不是一个好主意的原因之一。

    我要做的是尝试找出您使用非标准 SQL 的地方并重构您的代码以将这些部分移至专用服务。然后你可以在运行单元测试时模拟这些。

    【讨论】:

    • 在某些情况下仍然可能出现问题(例如,某些词在一个 DBMS 中是关键字,而在其他 DBMS 中则不是),使用不同的 DBMS 进行测试可能无法消除它们。跨度>
    • @Nicolae 显然,是的。您需要对这些方法进行专门的集成测试
    • 尝试使用自动递增的唯一 64 位密钥编写一个简单的表。很难找到比这更典型的表了。现在确保它适用于 PgSQL、MySQL、MsSQL 和 SQLite。祝你好运。
    【解决方案2】:

    您可以为 JUnit 测试使用不同的架构。如果您使用的是 Spring,它的 JUnit 扩展允许每个测试在只读事务中运行,因此测试后没有数据将持久保存在数据库中。如果您需要测试的初始数据,请将所需数据放在参与事务的@Before 标记方法中。

    【讨论】:

      【解决方案3】:

      你可以挂载一个ramdrive(使用ImDisk),在上面复制你的数据文件,并在my.cnf中更改适当的配置后启动Mysql服务 单元测试数据库通常很小(为了快速测试,您应该保持它们很小),它们通常可以放入内存驱动器中。

      您也可以考虑在 Spring 测试中使用事务,而不是在每次测试时重建表。

      我们将它用于我们的开发团队,它就像一个魅力,我们的速度提高了一个数量级。

      【讨论】:

        【解决方案4】:

        我们使用 MySQL 和 flyway 来处理迁移。

        对于单元测试和简单的集成测试,我们使用带有 MODE=MySQL 参数的 H2 内存数据库。 Mode=MySQL 使 H2 DB 能够处理大部分 MySQL 方言。

        我们在 Spring 配置中的测试数据源是这样设置的:

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" >
            <property name="driverClassName" value="org.h2.Driver"/>
            <property name="url" value="jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" />
        </bean>
        

        (如果您不了解 Spring - XML 转换为调用 new BasicDataSource,然后在创建的实例上调用 setDriverClassNamesetUrl

        然后我们在数据源上使用 Flyway 来创建模式并像我们对常规 MySQL DB 一样读取:

        <bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
            <property name="dataSource" ref="dataSource" />
            <property name="cleanOnValidationError" value="false" />
            <property name="initOnMigrate" value="true" />
            <property name="sqlMigrationSuffix" value=".ddl" />
        </bean>
        

        您也可以只在 jdbcTemplate 中使用 dataSource bean 并以这种方式运行一些 SQL 脚本,或者使用 &lt;jdbc:initialize-database...&gt; 标签运行一些 MySQL 脚本。

        【讨论】:

        • 很遗憾,H2 不支持很多语句,例如 UNIQUE KEYCREATE EVENTINSERT IGNORE
        • 但不是Mysql,还是容易出现不兼容问题
        • H2 也不支持 IF 函数 :( 原因:org.h2.jdbc.JdbcSQLException: Function "IF" not found; SQL statement: select if(len
        • H2 似乎也不支持 UNHEX 函数。
        • H2 甚至不支持枚举
        【解决方案5】:

        使用与 MySQL 完全兼容且可在 JUnit 测试用例中使用的内存数据库的最简单方法是 imho MariaDB4j。 您只需要一个 Gradle (/Maven) 依赖项 (http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22mariaDB4j%22) 和几行代码即可开始:

        DB database = DB.newEmbeddedDB(3306);
        database.start();
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "");
        

        一个启动脚本可以通过

        database.source("path/to/resource.sql");
        

        有关 GitHub 自述文件的更多信息: https://github.com/vorburger/MariaDB4j

        编辑: 我对此答案有一些提示:MariaDB4j 似乎在系统临时文件夹中添加了文件。因此它将以嵌入式方式工作,这意味着无需安装任何东西,您只需通过所需的构建工具使用依赖项即可。但这不是真正的仅内存解决方案,因此我们不能再谈论单元测试,因为单元测试不能依赖文件或数据库

        【讨论】:

          【解决方案6】:

          我建议使用基于 docker 的 mysql/postgres/DB 测试容器。

          Pom.xml

              <dependency>
                  <groupId>org.testcontainers</groupId>
                  <artifactId>postgresql</artifactId>
                  <version>1.15.1</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>org.testcontainers</groupId>
                  <artifactId>junit-jupiter</artifactId>
                  <version>1.15.1</version>
                  <scope>test</scope>
              </dependency>
          

          XyzIT.java

          @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
          @ActiveProfiles("test")
          @Testcontainers
          

          Application-test.yml

            datasource:
              initialization-mode: always
              schema: classpath*:schema-anyDb.sql  #initial sql script to createDB
              url: jdbc:tc:postgresql:11.9:///
            jpa:
              hibernate.ddl-auto: none
              properties:
                hibernate:
                  dialect: org.hibernate.dialect.PostgreSQLDialect
                  format_sql: true
                  default_schema: public
              show-sql: true
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-02-07
            • 1970-01-01
            • 1970-01-01
            • 2021-12-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多