Путь к XML DTD для DBUnit в многомодульном проекте Java / Maven? - PullRequest
9 голосов
/ 10 июня 2010

У меня есть мультимодульный проект Maven. В модуле persist у меня есть несколько файлов данных XML-файлов, которые ссылаются на DTD:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "myapp-data.dtd" >

<dataset>
      .....omitted for brevity....
</dataset>

DTD хранится в том же каталоге, что и файлы XML, и даже Eclipse сообщает эти файлы XML как действительные.

Однако, когда я запускаю приложение, DBUnit FlatXMLDataSet генерирует исключение FileNotFound, потому что не может найти DTD. По-видимому, он ищет DTD в корневом каталоге проекта (например, myproject /). Я ожидал, что он будет искать DTD в том же каталоге, что и сам файл XML (например, myproject / persist / target / test-data).

Глядя на исходный код DBUnit, он говорит об этом "Относительные URI DOCTYPE разрешены из текущей рабочей директории."

Какой хороший способ это исправить?

Ответы [ 5 ]

9 голосов
/ 13 июня 2010

ОК, думаю, я понял это. Слава Богу за открытый исходный код.

В FlatXmlDataSetBuilder существует метод, который передает поток в DTD. Это безумие, что это публичный метод IMO, но опять же, это безумие, что DBUnit не смотрит в тот же каталог, что и XML для файла dtd. Итак, вот оно:

String dtdResourceName = "classpath:test-data/myapp-data.dtd";      
Resource res = applicationContext.getResource(dtdResourceName);
builder.setMetaDataSetFromDtd(res.getInputStream());

Теперь я оставляю объявление DOCTYPE с dtd в том же каталоге, что и XML, и использую этот хак, чтобы обмануть DBUnit и сделать правильную вещь.

3 голосов
/ 11 июня 2010

Всегда используйте правильные переменные для доступа к специальным каталогам, поскольку многомодульные сборки имеют рабочий каталог, отличный от локальных:

Итак

  • вместо mydir используйте ${project.basedir}/mydir
  • вместо target/mydir используйте ${project.build.directory}/mydir
  • вместо target/classes/mydir используйте ${project.build.outputDirectory}/mydir

Эти переменные всегда вычисляются для текущего проекта, независимо от того, откуда он вызывается. Вот Обзор переменных POM (не полный, но самый важный материал там)

Кроме того, если вы когда-нибудь захотите выполнить некоторую интерактивную отладку в стиле запросов, вам подойдет help: оценивать mojo :

просто позвоните

mvn help:evaluate

и вам будет предложено выражение. Если вы введете выражение, например, ${project.build.plugins[0]}, объединенный домен для указанного элемента будет указан


EDIT:

хорошо, теперь я думаю, что вижу проблему. тогда почему бы просто не ссылаться на каталог в xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "target/test-classes/myapp-data.dtd" >

Я знаю, что это не красиво, но оно должно работать, многомодульное или нет. текущим каталогом для модульных тестов всегда является текущий $ {project.basedir}, а не каталог родительского проекта.

1 голос
/ 18 сентября 2013

Вы можете опубликовать DTD на веб-сервере и затем поместить его URL-адрес HTTP в DOCTYPE, например ::10000

<!DOCTYPE myapp-data SYSTEM "-//The Owner//The Description//EN" "http://host/path/to/myapp-data.dtd">
0 голосов
/ 18 сентября 2013

Это включает в себя некрасивое дублирование, но вы можете вставить содержимое DTD в соответствующий файл (ы) XML, а затем использовать их как внутренние DTD .

0 голосов
/ 15 февраля 2012

Попробуйте использовать «Файл» вместо «FileInputStream» при открытии файла XML.

Например:

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new File(fileName)));

Таким образом, относительный путь к DTD должен начинаться с каталога XML-файла.

А если вы используете

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new FileInputStream(fileName)));

путь должен быть относительно текущего рабочего каталога.

...