• 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

  • 相关阅读:
    ACM学习历程—UESTC 1219 Ba Gua Zhen(dfs && 独立回路 && xor高斯消元)
    ACM学习历程—BZOJ 2115 Xor(dfs && 独立回路 && xor高斯消元)
    ACM学习历程—HDU 5536 Chip Factory(xor && 字典树)
    ACM学习历程—HDU 5534 Partial Tree(动态规划)
    ACM学习历程—HDU 3949 XOR(xor高斯消元)
    CSS 负边距读后感
    移除input number上的spinner
    js另类值交换
    自己写js库,怎么支持AMD
    <strong>和 <b> 的区别
  • 原文地址:https://www.cnblogs.com/adaikiss/p/2482806.html
Copyright © 2020-2023  润新知