【问题标题】:How do I test with DBUnit with plain JDBC and HSQLDB without facing a NoSuchTableException?如何在不遇到 NoSuchTableException 的情况下使用纯 JDBC 和 HSQLDB 测试 DBUnit?
【发布时间】:2010-12-04 14:17:38
【问题描述】:

我正在尝试将 DBUnit 与普通的 JDBC 和 HSQLDB 一起使用,但并不能完全使其工作——即使我之前已将 DBUnit 与 Hibernate 一起使用并取得了巨大成功。代码如下:

import java.sql.PreparedStatement;
import org.dbunit.IDatabaseTester;
import org.dbunit.JdbcDatabaseTester;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.XmlDataSet;
import org.junit.Test;

public class DummyTest {

    @Test
    public void testDBUnit() throws Exception {
        IDatabaseTester databaseTester = new JdbcDatabaseTester("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem", "sa", "");
        IDataSet dataSet = new XmlDataSet(getClass().getResourceAsStream("dataset.xml"));
        databaseTester.setDataSet(dataSet);
        databaseTester.onSetup();
        PreparedStatement pst = databaseTester.getConnection().getConnection().prepareStatement("select * from mytable");
    }
}

这是有问题的 dataset.xml:

<dataset>
    <table name="mytable">
        <column>itemnumber</column>
        <column>something</column>
        <column>other</column>
        <row>
            <value>1234abcd</value>
            <value>something1</value>
            <value>else1</value>
        </row>
    </table>
</dataset>

这个测试给了我一个 NoSuchTableException:

org.dbunit.dataset.NoSuchTableException: mytable
    at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:282)
    at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:109)
    at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
    at org.dbunit.AbstractDatabaseTester.executeOperation(AbstractDatabaseTester.java:190)
    at org.dbunit.AbstractDatabaseTester.onSetup(AbstractDatabaseTester.java:103)
    at DummyTest.testDBUnit(DummyTest.java:18)

如果我删除 databaseTester.onSetup() 行,我会得到一个 SQLException:

java.sql.SQLException: Table not found in statement [select * from mytable]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.<init>(Unknown Source)
    at org.hsqldb.jdbc.jdbcConnection.prepareStatement(Unknown Source)
    at DummyTest.testDBUnit(DummyTest.java:19)

数据集本身正在运行,因为我可以正常访问它:

ITable table = dataSet.getTable("mytable");
String firstCol = table.getTableMetaData().getColumns()[0];
String tName = table.getTableMetaData().getTableName();

我在这里错过了什么?

编辑:正如@mlk 指出的,DBUnit 不创建表。如果我在添加数据集之前插入以下内容,一切都会顺利:

PreparedStatement pp = databaseTester.getConnection().getConnection().prepareStatement(
     "create table mytable ( itemnumber varchar(255) NOT NULL primary key, "
   + " something varchar(255), other varchar(255) )");
pp.executeUpdate();

我以Is there any way for DBUnit to automatically create tables from a dataset or dtd?发布了一个后续问题

【问题讨论】:

    标签: java jdbc junit hsqldb dbunit


    【解决方案1】:

    dbUnit 不创建表。 XML 文件中提供的有限信息也不可能。我相信 Hibernate 可以创建表格。

    这是我停止使用内存数据库并让 DBA 为每个开发人员提供自己的数据库的原因之一。然后,每个开发人员都使用相同的脚本来更新数据库,这些脚本稍后会实时运行。这会增加一点开销(所有开发人员都需要让他们的数据库保持最新),但这意味着您不必为每次运行都构建数据库而烦恼,并且您可以确保查询在实时测试工作中运行。

    第二个原因是速度。我发现创建内存数据库比简单地连接到现有数据库花费的时间要长得多。

    第三个原因是拆除是非破坏性的(启动会擦除数据库)。这意味着我可以在数据库上运行被测 SQL,以帮助找出测试失败的原因。


    更新:20171115

    我已经改用JUnit rules that start up a real instance of the database serverFlywayDB 之类的东西来构建数据库(并在实时和测试中使用相同的脚本,由应用程序负责构建数据库)。它比使用预建数据库要慢得多。但是,使用定义明确的微服务(从而减少需要测试的功能)并且非常严格地确定哪些测试可以获取数据库,您可以迁移此类问题并获得始终匹配实时的本地数据库的好处。

    这确实意味着测试拆除总是具有破坏性的,但是一个放置得当的断点可以解决这个问题。

    【讨论】:

    • 我现在已切换到在 VM 中运行的本地 Oracle XE 实例。这样做的原因是我们可以在不连接内部网络的情况下继续开发。
    • 有了内存数据库,我可以在任何地方运行单元测试,无需切换任何配置,也无需启动数据库服务器。它们主要在各种开发盒和 CI 服务器上运行。在我的书中,这是一个巨大的优势。
    • 是的。我个人发现它要慢得多,但是现在可能已经改变了。启动本地 VM 的 Oracle XE 实例所需的时间很短,每天一次。
    【解决方案2】:

    ...几年后我们有了更好的选择

    Spring Boot/Spring JDBC 可以使用普通 JDBC 初始化数据库。

    Spring JDBC 有一个 DataSource 初始化器特性。 Spring Boot 启用 默认情况下,它会从标准位置schema.sql 加载 SQL 和 data.sql(在类路径的根目录中)。此外,Spring Boot 将 加载 schema-${platform}.sqldata-${platform}.sql 文件(如果 present),其中平台是spring.datasource.platform 的值, 例如您可以选择将其设置为数据库的供应商名称 (hsqldb、h2、oracle、mysql、postgresql 等)。

    https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html

    【讨论】:

      【解决方案3】:

      如果您确实像建议的 here 那样预先创建了表,但仍然得到 NoSuchTableException,那么架构有问题。在你变得疯狂之前,以各种奇怪而奇妙的方式摆弄它,尝试在创建 IDatabaseConnection 时将架构参数设置为 PUBLIC,如下所示:

      IDatabaseConnection databaseConnection = new HsqldbConnection(sqlConnection, "PUBLIC");
      

      我用调试器逐步完成了 DbUnit 代码,但这似乎可以解决问题。

      【讨论】:

        猜你喜欢
        • 2020-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多