JUnit - Daten aus Xml, CSV, Json .. als Liste im Test bereitstellen

Mit Hilfe von DBUnit können Datenbanken mit Daten z.B. aus CSV oder XML Dateien vor einem Test befüllt werden. In einigen Testfällen werden aber auch Testdaten benötigt die sich noch nicht in der Datenbank befinden und nicht mit “SELECT” aus der Datenbank geholt werden sollten. Eine Möglichkeit ist, Objekte zu erstellen und die Attribute mit Daten zu befüllen. Ich habe mir mit Hilfe von DBUnit noch eine weitere Möglichkeit geschaffen. Ich lese Daten aus XML, CSV … etc. mit Hilfe von DBUnit ein und schreibe sie dann nicht in die Datenbank sondern gebe sie mir als Liste in der Testmethode aus. Das im Beispiel erwähnte JsonDataSet habe ich von danhaywood aus seinem Beitrag http://danhaywood.com/2011/12/20/db-unit-testing-with-dbunit-json-hsqldb-and-junit-rules/. Das Beispiel wurde mit einer Example Klasse (https://gist.github.com/itsei/b28ec83c00dae167f1eb#file-example-java) umgesetzt und entspricht dem Objekt der Testdaten. Alle folgende Dateien sind unter https://gist.github.com/itsei/b28ec83c00dae167f1eb zu finden. Um die Daten dynamisch später laden zu können benötigen wir ein Interface (https://gist.github.com/itsei/b28ec83c00dae167f1eb#file-dataloader-java) :

import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;

public interface DataLoader {

public <T> T generate() throws DataSetException;

public void setData(IDataSet dataSet);

public void clean();

}

Für unsere Example Klasse benötigen wir jetzt noch die entsprechende Implementierung des Loaders, ExampleLoaderImpl.java (https://gist.github.com/itsei/b28ec83c00dae167f1eb#file-exampleloaderimpl-java). Dabei sollte je nach Attribute Type der folgende Code noch erweitert werden (teil Ausschnitt, kompletter Code siehe Link:

field = Example.class.getDeclaredField(column.getColumnName());
field.setAccessible(true);
String columnValue = (String) table.getValue(i, column.getColumnName());
if(field.getType().isAssignableFrom(Long.class)) {
field.set(example, Long.valueOf(columnValue));
} else if (field.getType().isAssignableFrom(Integer.class)) {
field.set(example, Integer.valueOf(columnValue));
} else {
field.set(example, columnValue);
}

Damit wird die Daten nun aber auch laden können, wird die Klasse DataLoaderStatement benötigt (https://gist.github.com/itsei/b28ec83c00dae167f1eb#file-dataloaderstatement-java). Diese Klasse wird später als Rule eingebunden und die Dateien mit den Testdaten mit den Annotationen angeben. Der folgende Code zeigt exemplarisch das Laden einer XML Datei (für den Rest siehe Link):

DataLoaderXml xmlData = method.getAnnotation(DataLoaderXml.class);
if(xmlData != null) {
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
InputStream inputStream = resourceBase.getResourceAsStream(xmlData.value());
loader.setData(builder.build(inputStream));
}

Die CSV Implementierung kann durch kopieren des JsonDataSets einfach realisiert werden. Dazu muss einfach nur die getTable Methode angepasst werden:

public List getTables(InputStream csvStream, String tableName) {
List tables = new ArrayList();
try {
// get the base object tree from the JSON stream
Reader reader = new InputStreamReader(csvStream);

    CSVReader<String\[\]> csvParser = CSVReaderBuilder.newDefaultReader(reader);
    List<String\[\]> datas = csvParser.readAll();
    //FirsrRow title
    Map<Long,String> headline = new HashMap<Long, String>();
    List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
    if(datas != null && !datas.isEmpty()) {
        String\[\] data =  datas.get(0);
        if(data != null) {
        for (int index = 0; index < data.length; index++) {
            String dataContent = data\[index\];
            headline.put(Long.valueOf(index), dataContent);
        }
        }
    }
    for (int index = 1; index < datas.size(); index++) {
        String\[\] data = datas.get(index);
        Map<String,Object> dataMap = new HashMap<String, Object>();
        for (int ii = 0; ii < data.length; ii++) {
        String dataContent = data\[ii\];
        dataMap.put(headline.get(Long.valueOf(ii)), dataContent);
        }
        rows.add(dataMap);
    }
    ITableMetaData meta = getMetaData(tableName, rows);

    // iterate over the tables in the object tree
    DefaultTable table = new DefaultTable(meta);
    int rowIndex = 0;
    // iterate through the rows and fill the table
    for (Map<String, Object> row : rows) {
        fillRow(table, row, rowIndex++);
    }
    // add the table to the list of DBUnit tables
    tables.add(table);

    } catch (IOException e) {
    throw new RuntimeException(e.getMessage(), e);
    }
    return tables;
}

Die Einbindung in einen JUnit Test sieht dann wie folgt aus (https://gist.github.com/itsei/b28ec83c00dae167f1eb#file-exampletest-java) :

@DataLoaderXml(“sampleTestData.xml”)
@DataLoaderCsv(“sampleTestData.csv”)
public void checkValues() throws MalformedURLException, DataSetException {
List datas = (List) dataLoader.getData();
assertEquals(datas.get(0).getName(), “example”);
assertEquals(datas.get(0).getVersion(), Long.valueOf(0L));
}

Maven Dependencies:


org.dbunit
dbunit
2.4.9
jar
test


junit
junit
4.11
test


commons-collections
commons-collections
3.2.1

For english: How you can load data from files for tests? I have write an example to load data as array list in test cases. You can find all files under https://gist.github.com/itsei/b28ec83c00dae167f1eb.