Как проверить с помощью DBUnit с помощью простых JDBC и HSQLDB, не сталкиваясь с NoSuchTableException?
Я пытаюсь использовать 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();
Что мне здесь не хватает?
EDIT. Как указывает @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?
Ответы
Ответ 1
dbUnit не создает таблицы. И это не могло быть связано с ограниченной информацией, приведенной в файле XML. Спящий режим, я считаю, может создавать таблицы.
Это одна из причин, по которой я прекратил использование баз данных в памяти и вместо этого получил администратор баз данных, чтобы предоставить каждому разработчику собственную базу данных. Затем каждый разработчик обновляет базу данных, используя те же сценарии, которые впоследствии запускаются в режиме реального времени. Это добавляет небольшие накладные расходы (всем разработчикам необходимо обновлять свои базы данных), но означает, что вам не нужно путаться в создании базы данных для каждого прогона, и вы можете быть уверены, что запросы выполнялись в тестовой работе в режиме реального времени.
Вторая причина - скорость. Я обнаружил, что создание базы данных в памяти заняло гораздо больше времени, чем просто подключение к существующей базе данных.
Третья причина заключалась в том, что срыв не является разрушительным (запуск стирает базу данных). Это означает, что я могу запустить SQL-тест в базе данных, чтобы помочь решить, почему тест терпит неудачу.
Обновление: 20171115
С тех пор я переключился на использование правил JUnit, которые запускают настоящий экземпляр сервера баз данных и что-то вроде FlywayDB для создания базы данных (и с использованием тех же сценариев, что и в тесте, с приложением, ответственным за создание базы данных). Это значительно медленнее, чем использование предварительно созданной базы данных. Однако, используя хорошо определенные микросервисы (и, следовательно, уменьшая функциональность, требующую тестирования) и будучи очень плотно, на каких тестах получает базу данных, вы можете перенести такие проблемы и получить преимущества локальной базы данных, которая всегда соответствует живым.
Это, конечно, означает, что тестовый разрыв всегда разрушительный, но хорошо подобранная точка прерывания решает это.
Ответ 2
... через несколько лет у нас появились лучшие варианты
Spring Загрузка / Spring JDBC может инициализировать базу данных с помощью простого JDBC.
Spring JDBC имеет функцию инициализатора DataSource. Spring Загрузка позволяет по умолчанию и загружает SQL из стандартных местоположений schema.sql
и data.sql
(в корне пути к классам). Кроме того, Spring Boot будет загрузите файлы schema-${platform}.sql
и data-${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
Если вы создадите свои таблицы вверх, например, предлагаемые здесь, и по-прежнему получите исключение NoSuchTableException, то что-то не так с схемой. Прежде чем вы теперь сходите с ума, возитесь с ним всякими странными и замечательными способами, попробуйте установить параметр схемы PUBLIC при создании IDatabaseConnection
, например:
IDatabaseConnection databaseConnection = new HsqldbConnection(sqlConnection, "PUBLIC");
Мне потребовался некоторый шаг через код DbUnit с отладчиком, но это, похоже, делает трюк.