Как мне протестировать с DBUnit с простым JDBC и HSQLDB, не сталкиваясь с NoSuchTableException? - PullRequest
16 голосов
/ 07 октября 2009

Я пытаюсь использовать 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();

Я опубликовал следующий вопрос как Можно ли DBUnit автоматически создавать таблицы из набора данных или dtd?

Ответы [ 3 ]

19 голосов
/ 07 октября 2009

dbUnit не создает таблицы. Не может это и с ограниченной информацией, указанной в файле XML. Я уверен, что Hibernate может создавать таблицы.

Это одна из причин, по которой я прекратил использовать базы данных в памяти и вместо этого попросил администратора баз данных предоставить каждому разработчику свою собственную базу данных. Затем каждый разработчик обновляет базу данных, используя те же сценарии, которые впоследствии запускаются вживую. Это добавляет небольшие накладные расходы (все разработчики должны поддерживать свои базы данных в актуальном состоянии), но означает, что вам не нужно возиться с созданием базы данных для каждого запуска, и вы можете быть уверены, что запросы выполнялись в тестовой работе вживую.

Вторая причина была скорость. Я обнаружил, что создание базы данных в памяти заняло гораздо больше времени, чем простое подключение к существующей базе данных.

Третья причина была в том, что разрыв не является разрушительным (запуск стирает базу данных). Это означает, что я могу запустить тестируемый SQL в базе данных, чтобы понять, почему тест не пройден.


Обновление : 20171115

С тех пор я перешел на использование правил JUnit, которые запускают реальный экземпляр сервера базы данных и что-то вроде FlywayDB для построения базы данных (и с использованием тех же сценариев в прямом эфире). как в тесте, с приложением, ответственным за создание базы данных). Это значительно медленнее, чем использование готовой базы данных. Однако, используя четко определенные микросервисы (и, таким образом, сокращая функциональность, требующую тестирования) и будучи очень внимательным в отношении того, какие тесты получают базу данных, вы можете переносить такие проблемы и получать преимущества локальной базы данных, которая всегда соответствует действующей.

Это, увы, означает, что тестовый разрыв всегда разрушителен, но удачно расположенная точка останова решает это.

4 голосов
/ 03 мая 2016

... через несколько лет у нас есть лучшие варианты

Spring Boot / Spring JDBC может инициализировать базу данных с простым JDBC.

Spring JDBC имеет функцию инициализатора источника данных. Spring Boot позволяет он по умолчанию загружает SQL из стандартных местоположений schema.sql и data.sql (в корне пути к классам). Кроме того, Spring Boot будет загрузить файлы schema-${platform}.sql и data-${platform}.sql (если настоящее время), где платформой является значение spring.datasource.platform, например Вы можете установить его в качестве имени поставщика базы данных (hsqldb, h2, oracle, mysql, postgresql и т. д.).

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

0 голосов
/ 20 сентября 2010

Если вы создаете свои таблицы заранее, как предложено здесь , и по-прежнему получаете исключение NoSuchTableException, то в схеме что-то не так. Прежде чем вы сейчас сойдете с ума, возитесь с ним всевозможными странными и чудесными способами, попробуйте установить параметр схемы в PUBLIC при создании IDatabaseConnection, например:

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

Мне потребовалось немного пройтись по коду DbUnit с помощью отладчика, но, похоже, это сработало.

...