DbUnit自定义data file格式

DbUnit测试数据XML格式常用的就两种,FlatXmlDataset和XmlDataSet:

<dataset>

  <USER USER_ID="1" USER_NAME="ZhuTou" PASSWORD="zt"/>

</dataset>
<dataset>

  <table name="USER">

    <column>USER_ID</column>

    <column>USER_NAME</column>

    <column>PASSWORD</column>

    <row>

      <value>1</value>

      <value>ZhuTou</value>

      <value>zt</value>

    </row>

  </table>

</dataset>

第一种比较简洁,某些空的字段可以直接不写,但是不支持CDATA,如果有些数据较长或是二进制需要使用BASE64编码,就用不了了。

第二种就是支持CDATA,缺点是空的字段也要写一个<NULL/>或<NONE/>,不能少,顺序也要和column定义一致,不能乱。这样不但烦琐(特别是某些表很多字段可能为空的情况),还容易出错,一堆数据很难看出哪行是对应哪一个字段的。

我期望的格式是

<dataset>

  <table name="user">

    <column>user_id</column>

    <column>user_name</column>

    <column>password</column>

    <column>address</column>

    <column>remark</column>

    <row>

      <value name="user_id">1</value>

      <value name="user_name">ZhuTou</value>

      <value name="password"><![CDATA[jfl3<0d/;]]></value>

    </row>

    ...

  </table>

<dataset>

而且row里的的顺序可以乱排。

看了DBUNIT部分代码(主要是org.dbunit.dataset.xml.XmlProducer和org.dbunit.dataset.xml.XmlDataSet),只要自己实现一个XmlProducer就可以了,不过因为XmlDataSet里无法指定producer所以只要把XmlDataSet也重写一个。

CustomXmlProducer:

  1 import java.io.IOException;

  2 import java.io.InputStream;

  3 import java.util.HashMap;

  4 import java.util.LinkedList;

  5 import java.util.List;

  6 import java.util.Map;

  7 

  8 import javax.xml.parsers.ParserConfigurationException;

  9 import javax.xml.parsers.SAXParserFactory;

 10 

 11 import org.dbunit.dataset.Column;

 12 import org.dbunit.dataset.DataSetException;

 13 import org.dbunit.dataset.DefaultTableMetaData;

 14 import org.dbunit.dataset.ITableMetaData;

 15 import org.dbunit.dataset.datatype.DataType;

 16 import org.dbunit.dataset.stream.DefaultConsumer;

 17 import org.dbunit.dataset.stream.IDataSetConsumer;

 18 import org.dbunit.dataset.stream.IDataSetProducer;

 19 import org.slf4j.Logger;

 20 import org.slf4j.LoggerFactory;

 21 import org.xml.sax.Attributes;

 22 import org.xml.sax.ContentHandler;

 23 import org.xml.sax.ErrorHandler;

 24 import org.xml.sax.InputSource;

 25 import org.xml.sax.SAXException;

 26 import org.xml.sax.SAXParseException;

 27 import org.xml.sax.XMLReader;

 28 import org.xml.sax.helpers.DefaultHandler;

 29 

 30 public class CustomXmlProducer extends DefaultHandler implements

 31         IDataSetProducer, ContentHandler, ErrorHandler {

 32 

 33     /**

 34      * Logger for this class

 35      */

 36     private static final Logger logger = LoggerFactory

 37             .getLogger(CustomXmlProducer.class);

 38 

 39     private static final IDataSetConsumer EMPTY_CONSUMER = new DefaultConsumer();

 40 

 41     private static final String DATASET = "dataset";

 42     private static final String TABLE = "table";

 43     private static final String NAME = "name";

 44     private static final String COLUMN = "column";

 45     private static final String ROW = "row";

 46     private static final String VALUE = "value";

 47 //    private static final String NULL = "null";

 48 //    private static final String NONE = "none";

 49 

 50     private static final String COLUMN_ATTR_NAME = "name";

 51 

 52     private final InputSource _inputSource;

 53     private boolean _validating = false;

 54 

 55     private IDataSetConsumer _consumer = EMPTY_CONSUMER;

 56 

 57     private String _activeTableName;

 58     private ITableMetaData _activeMetaData;

 59 

 60     private List<String> _activeColumnNames;

 61     private StringBuffer _activeCharacters;

 62 //    private List _activeRowValues;

 63 

 64     private Map<String, String> _activeRowValues;

 65     private String _activeColumnName;

 66     private List<String> __activeColumnNames;

 67 

 68     public CustomXmlProducer(InputSource inputSource) {

 69         _inputSource = inputSource;

 70     }

 71 

 72     private ITableMetaData createMetaData(String tableName, List<String> columnNames) {

 73         logger.debug("createMetaData(tableName={}, _columnNames={}) - start",

 74                 tableName, columnNames);

 75 

 76         Column[] columns = new Column[columnNames.size()];

 77         for (int i = 0; i < columns.length; i++) {

 78             String columnName = (String) columnNames.get(i);

 79             columns[i] = new Column(columnName, DataType.UNKNOWN);

 80         }

 81         DefaultTableMetaData metaData = new DefaultTableMetaData(tableName,

 82                 columns);

 83         return metaData;

 84     }

 85 

 86     public void setValidating(boolean validating) {

 87         _validating = validating;

 88     }

 89 

 90     // //////////////////////////////////////////////////////////////////////////

 91     // IDataSetProducer interface

 92 

 93     public void setConsumer(IDataSetConsumer consumer) throws DataSetException {

 94         logger.debug("setConsumer(consumer={}) - start", consumer);

 95         _consumer = consumer;

 96     }

 97 

 98     public void produce() throws DataSetException {

 99         logger.debug("produce() - start");

100 

101         try {

102             SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

103             saxParserFactory.setValidating(_validating);

104             XMLReader xmlReader = saxParserFactory.newSAXParser()

105                     .getXMLReader();

106 

107             xmlReader.setContentHandler(this);

108             xmlReader.setEntityResolver(this);

109             xmlReader.setErrorHandler(this);

110             xmlReader.parse(_inputSource);

111         } catch (ParserConfigurationException e) {

112             throw new DataSetException(e);

113         } catch (SAXException e) {

114             DataSetException exceptionToRethrow = CustomXmlProducer

115                     .buildException(e);

116             throw exceptionToRethrow;

117         } catch (IOException e) {

118             throw new DataSetException(e);

119         }

120     }

121 

122     /**

123      * Wraps a {@link SAXException} into a {@link DataSetException}

124      * 

125      * @param cause

126      *            The cause to be wrapped into a {@link DataSetException}

127      * @return A {@link DataSetException} that wraps the given

128      *         {@link SAXException}

129      */

130     protected final static DataSetException buildException(SAXException cause) {

131         int lineNumber = -1;

132         if (cause instanceof SAXParseException) {

133             lineNumber = ((SAXParseException) cause).getLineNumber();

134         }

135         Exception exception = cause.getException() == null ? cause : cause

136                 .getException();

137         String message;

138 

139         if (lineNumber >= 0) {

140             message = "Line " + lineNumber + ": " + exception.getMessage();

141         } else {

142             message = exception.getMessage();

143         }

144 

145         if (exception instanceof DataSetException) {

146             return (DataSetException) exception;

147         } else {

148             return new DataSetException(message, exception);

149         }

150     }

151 

152     // //////////////////////////////////////////////////////////////////////////

153     // EntityResolver interface

154 

155     public InputSource resolveEntity(String publicId, String systemId)

156             throws SAXException {

157         logger.debug("resolveEntity(publicId={}, systemId={}) - start",

158                 publicId, systemId);

159 

160         InputStream in = getClass().getClassLoader().getResourceAsStream(

161                 "org/dbunit/dataset/xml/dataset.dtd");

162         return (new InputSource(in));

163     }

164 

165     // //////////////////////////////////////////////////////////////////////

166     // ContentHandler interface

167 

168     public void startElement(String uri, String localName, String qName,

169             Attributes attributes) throws SAXException {

170         if (logger.isDebugEnabled()) {

171             logger.debug(

172                     "startElement(uri={}, localName={}, qName={}, attributes={}) - start",

173                     new Object[] { uri, localName, qName, attributes });

174         }

175 

176         try {

177             // dataset

178             if (qName.equals(DATASET)) {

179                 _consumer.startDataSet();

180                 return;

181             }

182 

183             // table

184             if (qName.equals(TABLE)) {

185                 _activeTableName = attributes.getValue(NAME);

186                 _activeColumnNames = new LinkedList<String>();

187                 return;

188             }

189 

190             // column

191             if (qName.equals(COLUMN)) {

192                 _activeCharacters = new StringBuffer();

193                 return;

194             }

195 

196             // row

197             if (qName.equals(ROW)) {

198                 // End of metadata at first row

199                 if (_activeColumnNames != null) {

200                     _activeMetaData = createMetaData(_activeTableName,

201                             _activeColumnNames);

202                     _consumer.startTable(_activeMetaData);

203                     

204                     __activeColumnNames = _activeColumnNames;

205                     _activeColumnNames = null;

206                 }

207 

208 //                _activeRowValues = new LinkedList();

209                 _activeRowValues = new HashMap<String, String>();

210                 return;

211             }

212 

213             // value

214             if (qName.equals(VALUE)) {

215                 _activeColumnName = attributes.getValue(COLUMN_ATTR_NAME);

216                 _activeCharacters = new StringBuffer();

217                 return;

218             }

219 

220 //            // null

221 //            if (qName.equals(NULL)) {

222 //                _activeRowValues.add(null);

223 //                return;

224 //            }

225 //

226 //            // none

227 //            if (qName.equals(NONE)) {

228 //                _activeRowValues.add(ITable.NO_VALUE);

229 //                return;

230 //            }

231         } catch (DataSetException e) {

232             throw new SAXException(e);

233         }

234     }

235 

236     public void endElement(String uri, String localName, String qName)

237             throws SAXException {

238         if (logger.isDebugEnabled()) {

239             logger.debug("endElement(uri={}, localName={}, qName={}) - start",

240                     new Object[] { uri, localName, qName });

241         }

242 

243         try {

244             // dataset

245             if (qName.equals(DATASET)) {

246                 _consumer.endDataSet();

247                 return;

248             }

249 

250             // table

251             if (qName.equals(TABLE)) {

252                 __activeColumnNames = null;

253                 // End of metadata

254                 if (_activeColumnNames != null) {

255                     _activeMetaData = createMetaData(_activeTableName,

256                             _activeColumnNames);

257                     _consumer.startTable(_activeMetaData);

258                     _activeColumnNames = null;

259                 }

260 

261                 _consumer.endTable();

262                 _activeTableName = null;

263                 _activeMetaData = null;

264                 return;

265             }

266 

267             // column

268             if (qName.equals(COLUMN)) {

269                 _activeColumnNames.add(_activeCharacters.toString());

270                 _activeCharacters = null;

271                 return;

272             }

273 

274             // row

275             if (qName.equals(ROW)) {

276                 final int length = __activeColumnNames.size();

277                 Object[] values = new Object[length];

278 //                for (int i = 0; i < values.length; i++) {

279 //                    values[i] = (i >= _activeRowValues.size()) ? ITable.NO_VALUE

280 //                            : _activeRowValues.get(i);

281 //                }

282                 for(int i = 0;i < length; i ++){

283                     values[i] = _activeRowValues.get(__activeColumnNames.get(i));

284                 }

285                 _consumer.row(values);

286                 _activeRowValues = null;

287                 return;

288             }

289 

290             // value

291             if (qName.equals(VALUE)) {

292                 _activeRowValues.put(_activeColumnName, _activeCharacters.toString());

293                 _activeColumnName = null;

294                 _activeCharacters = null;

295                 return;

296             }

297 

298 //            // null

299 //            if (qName.equals(NULL)) {

300 //                // Nothing to do, already processed in startElement()

301 //                return;

302 //            }

303 //

304 //            // none

305 //            if (qName.equals(NONE)) {

306 //                // Nothing to do, already processed in startElement()

307 //                return;

308 //            }

309         } catch (DataSetException e) {

310             throw new SAXException(e);

311         }

312     }

313 

314     public void characters(char ch[], int start, int length)

315             throws SAXException {

316         if (_activeCharacters != null) {

317             _activeCharacters.append(ch, start, length);

318         }

319     }

320 

321     public void error(SAXParseException e) throws SAXException {

322         throw e;

323     }

324 

325 }

原来value是读到一个list里的,然后和column比较,少的部分用空的Object填,我改成先把value根据name属性放到一个map中,最后再放到一个数组,map中没有的值就是null。

CustomXmlDataSet:

 1 import java.io.InputStream;

 2 import java.io.Reader;

 3 

 4 import org.dbunit.dataset.CachedDataSet;

 5 import org.dbunit.dataset.DataSetException;

 6 import org.xml.sax.InputSource;

 7 

 8 /**

 9  * @author hlw

10  * 

11  */

12 public class CustomXmlDataSet extends CachedDataSet {

13 

14     /**

15      * Creates an XmlDataSet with the specified xml reader.

16      */

17     public CustomXmlDataSet(Reader reader) throws DataSetException {

18         super(new CustomXmlProducer(new InputSource(reader)));

19     }

20 

21     /**

22      * Creates an XmlDataSet with the specified xml input stream.

23      */

24     public CustomXmlDataSet(InputStream in) throws DataSetException {

25         super(new CustomXmlProducer(new InputSource(in)));

26     }

27 

28 }

这个类就是把默认的super(new XmlProducer(...))改成super(new CustomXmlProducer(...))。

 

然后在使用的时候

InputStream input = resourceLoader.getResource(xmlPath)

                        .getInputStream();

IDataSet dataset = new CustomDataSet(input);

还是和原来的用法一样。

 

另外如果测试数据有相互的外键引用的话,会插不进去,这时可以把数据库的约束检查关掉,对于mysql可以在connection url后面加上sessionVariables=FOREIGN_KEY_CHECKS=0

如jdbc.url=jdbc\:mysql\://localhost\:3306/test?sessionVariables=FOREIGN_KEY_CHECKS=0

 

你可能感兴趣的:(dbunit)