如何使用纯JDBC和HSQLDB使用DBUnit进行测试而不会遇到NoSuchTableException?

neu*_*242 16 java junit dbunit jdbc hsqldb

我正在尝试将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");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有问题的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>
Run Code Online (Sandbox Code Playgroud)

这个测试给了我一个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)
Run Code Online (Sandbox Code Playgroud)

如果我删除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)
Run Code Online (Sandbox Code Playgroud)

数据集本身正在工作,因为我可以像它应该那样访问它:

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

我在这里错过了什么?

编辑:正如@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();
Run Code Online (Sandbox Code Playgroud)

我发布了一个后续问题,因为DBUnit有没有办法从数据集或dtd自动创建表?

Mic*_*mlk 19

dbUnit不会创建表.也不能使用XML文件中给出的有限信息.我相信Hibernate可以创建表.

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

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

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


更新:20171115

我已经切换到使用 JUnit规则启动数据库服务器的实际实例以及FlywayDB之类的东西来构建数据库(并使用与测试中相同的脚本,应用程序负责构建数据库).它比使用预建数据库慢得多.但是,如果使用定义良好的微服务(以及减少需要测试的功能)并且对哪些测试获取数据库非常紧密,您可以迁移此类问题并获得始终与实时匹配的本地数据库的好处.

它确实意味着测试拆除总是具有破坏性,但是一个良好的断点可以解决这个问题.

  • 使用内存数据库,我可以在任何地方运行单元测试,而无需切换任何配置,也无需启动数据库服务器.它们主要在各种开发盒和CI服务器上运行.这在我的书中是一个巨大的优势. (3认同)