org.dbunit.dataset.NoSuchTableException: Did not f

2019-01-18 13:56发布

I know there have been discussions wrt to dbunit here. I have read most of them but I cant seem to find a solution to my problem.

I have set up hibernate and spring. I am doing TDD so I had to wire up a proper DAO testing framework before writing code. Dbunit came to mind and I got to setting it up. Here is ma testdataset.xml

    <?xml version='1.0' encoding='UTF-8'?>
    <dataset>
        <table name="status">
            <column>statusId</column>
            <column>status</column>
            <row>
                <value>0</value>
                <value>Available</value>
            </row>
        </table>
        <table name="user">
            <column>userId</column>
            <column>firstName</column>
            <column>lastName</column>
            <column>username</column>
            <column>password</column>
            <column>email</column>
            <row>
                <value>0</value>
                <value>system</value>
                <value>admin</value>
                <value>admin</value>
                <value>admin</value>
                <value>admin@ccbs.com</value>
            </row>
        </table>
        <table name="reservation">
            <column>reservationId</column>
            <column>userId</column>
            <column>reservationDate</column>
            <column>startDate</column>
            <column>endDate</column>
            <column>statusId</column>
            <row>
                <value>0</value>
                <value>0</value>
                <value>2011-02-20 12:46:00.0</value>
                <value>2011-03-01 12:00:00.0</value>
                <value>2011-04-01 12:00:00.0</value>
                <value>0</value>
            </row>
        </table>
    </dataset>

All seems well until i try to wire up some code using a base class that loads the dataset. Here is my code:

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:test-applicationContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class BaseContextSensitiveTest {

    @BeforeClass
public static void setUpDatabase() throws Exception {
    URL file = getInitalDatasetURL();
    testDataset = createDataset(file);
}

   @Before
public void init() throws Exception {
    log.info("Initializing Data Set");
    connection = createDBUnitConnection();

    DatabaseOperation.CLEAN_INSERT.execute(connection, testDataset);
}

private static URL getInitalDatasetURL() throws FileNotFoundException {
    URL file = ClassLoader.getSystemResource(TEST_DATASET_LOCATION);
    if (file == null) {
        throw new FileNotFoundException("Unable to find '"
                + TEST_DATASET_LOCATION + "' in the classpath");
    }
    return file;
}

private static IDataSet createDataset(URL file) throws IOException,
        DataSetException {

    return new XmlDataSet(file.openStream());
}

private IDatabaseConnection createDBUnitConnection()
        throws DatabaseUnitException, SQLException {

    Connection connection = getConnection();
    IDatabaseConnection dbUnitConn = new DatabaseConnection(connection);

    // use the hsql datatypefactory so that boolean properties work
    // correctly
    DatabaseConfig config = dbUnitConn.getConfig();
    config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
            new HsqldbDataTypeFactory());

    return dbUnitConn;
}

As soon as it hits the DatabaseOperation.CLEAN_INSERT.execute(connection, testDataset); it throws the following exception:

org.dbunit.dataset.NoSuchTableException: Did not find table 'USER' in schema 'null'
at org.dbunit.database.DatabaseTableMetaData.<init>(DatabaseTableMetaData.java:142)
at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:290)
at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:109)
at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
at com.cottage.test.BaseContextSensitiveTest.init(BaseContextSensitiveTest.java:64)

I have all the hibernate mapping files in place and the database is already set up with no data. Funny thing (or annoying thing depending on how you look at it) is that if I change the order of the tables in the dataset, the missingtableexception complains of another table... either user, reservation or status.

Any suggestions on what I might be doing wrong?

6条回答
狗以群分
2楼-- · 2019-01-18 14:35

I've also come across this same error and the accepted fix above did not fix my problems. However I was able to find the solution.

My setup consisted of DBUnit(2.4), EclipseLink(2.1) as my JPA provider, and Postgres as my backend database. Also, in my scenario I was not dropping and recreating the tables for each test run. My test data already existed. Bad practice I know, but it was more of a test/prototyping scenario. The code below illustrates the DBUnit configuration used to fix my problem.

54    // ctx represents a spring context
55    DataSource ds = (DataSource)ctx.getBean("myDatasourceBean");
56    Connection conn = DataSourceUtils.getConnection(ds);
57    IDatabaseConnection dbUnitConn = new DatabaseConnection(conn, "public");
58    DatabaseConfig dbCfg = dbUnitConn.getConfig();
59    dbCfg.setFeature(DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.TRUE);
60    IDataSet dataSet = new FlatXmlDataSet(ClassLoader.getSYstemResourceAsStream("mydbunitdata.xml"));
61    DatabaseOperation.REFRESH.execute(dbUnitConn, dataSet);

Two things in the code above fixed my problem. First I needed to define the schema DBUnit should use. That is done on line 57 above. When the new DatabaseConnection is set, the schema("public") should be passed in if it is not null.

Secondly, I needed DBUnit to be case sensitive about the database table names. In my DBUnit xml file("mydbunitdata.xml") the table names are all lowercase like they are in the database. However, if you don't tell DBUnit to use case sensitive table names it looks for uppercase table names which Postgres didn't like. Therefore I needed to set the case sensitive feature in DBUnit which is done on line 59.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-18 14:40

remove the first line in your dataset.xml file

<!DOCTYPE dataset>

and replace it with this

<?xml version='1.0' encoding='UTF-8'?>

otherwise DBUnit tries to load the db tables schema from a DTD file and if no DTD is provided it will never match on any tables. Using the plain xml header will cause DBUnit to skip this DTD - table check that is throwing the error you see.

You must also do what Grzegorz did and have hibernate do a create-drop for your tables by including

<property name="hibernate.hbm2ddl.auto" value="create-drop"/>

or

configuration.setProperty(Environment.HBM2DDL_AUTO, "create-drop");

查看更多
SAY GOODBYE
4楼-- · 2019-01-18 14:44

DBUnit will not create database tables for you because it has limited information from the dataset xml to create the intended database schema.

When used in tandem with hibernate, it will require proper hbm mapping files for every pojo (that you are trying to map to the in memory test database tables), which is ultimately used in the tests. Without the mapping files, you will get the org.dbunit.dataset.NoSuchTableException: Did not find table 'xxx' in schema 'yyy'.

Also, a valid hibernate.cfg.xml is required, correctly configured with all the hibernate mapping files.

You can delegate the database creation to hibernate by setting this property hibernate.hbm2ddl.auto=create-drop in your properties file.

The error message is a little misleading. Should probably contain more information to the effect of missing hibernate mapping files -- but this is a discussion on the DBunit wiki.

查看更多
爷、活的狠高调
5楼-- · 2019-01-18 14:52

You may be interested in this. I found this error also and by renaming my table in the hibernate.cfg.xml from 'message' to 'MESSAGE', It was able to find the schema.

Let me know if this works for you too.

查看更多
放我归山
6楼-- · 2019-01-18 14:55

Have you created the database tables in your database?

dbunit won't do it for you, because it doesn't know the intended database structure. However you can ask Hibernat to do it. Use the hbm2ddl flag, e.g.:

 <property name="hibernate.hbm2ddl.auto" value="create-drop"/>

I couldn't find the main documentation for the flag, but if you searched for it you would get a lot of results, incl. http://docs.jboss.org/ejb3/docs/reference/build/reference/en/html/entityconfig.html

查看更多
The star\"
7楼-- · 2019-01-18 14:56

I ran into the same error and had both my entity configured in hibernate.cfg.xml and I was using hbm2ddl to generate the tables, so I searched on and found that my entity mapping contained a field named "POSITION" which is a reserved term. When I changed it to "POS" the table was generated correctly.

You can check if your table is being generated by debugging the resultSet iteration in

org.dbunit.database.DatabaseDataSet.initialize().

查看更多
登录 后发表回答