# DBUnit und null



## nieselfriem (24. Jun 2021)

Hallo Zusammen,

ich möchte mit DBUit meine Datenbankeintragungen mal testen. Ist eigentlich recht einfach zu verstehen was da so passiert. Aber mit der definition von Null-Werten habe ich meine Probleme

Wie definiere ich in meine XML, dass die Tabelle auch nullwerte haben darf? Den Eintrag in der Dokumentation verstehe ich einfach nicht

IN dieser steht, ich soll das Attribut einfach weg lassen. Dann bekomme ich aber eine Fehlermeldung, dass die Attribute aus der Datenbank (column count) sich nicht mit der XML decken würden.


```
<dataset>
    <Produktbestellung prodbestId="1" datum_erzeugt="2021-06-21" datum_versendet="[null]" datum_geliefert="[null]"
                       gesamtpreis="7900" kunde="6" status="0" versandkosten="950" bestellnummer="2021062115086"
                       shop="1" bestellnummerextshop="12345-etsy" versandkostenid="4" datum_storniert="[null]"
                       datum_wideruf="[null]"/>
</dataset>
```

Was muss ich tun, damit die Nullwerte für den test akzeptiert werden?

VG niesel


----------



## LimDul (24. Jun 2021)

Zeig mal die genaue Fehlermeldung und den genauen Code.


----------



## nieselfriem (25. Jun 2021)

Das Datset mit dem ich die Tabelle füllen möchte
[CODE lang="xml" title="dataset"]<dataset>
    <Produkt prodId="1" preis="1250" bezeichnung="Supercollier" beschreibung=""  anzahl="4"  kategorie="1" unterkategorie="1" artikelnummer="CO1"/>
    <Produkt prodId="2" preis="4450" bezeichnung="Kette3" beschreibung=""  anzahl="0"  kategorie="1" unterkategorie="1" artikelnummer="HK2"/>
    <Produkt prodId="3" preis="5490" bezeichnung="Ring4" beschreibung=""  anzahl="1"  kategorie="1" unterkategorie="1" artikelnummer="RI1"/>
</dataset>[/CODE]

Das zu erwartende Dataset:


```
<dataset>
    <Produktbestellung prodbestId="1" datum_erzeugt="2021-06-21"
                       gesamtpreis="7900" kunde="6" status="0" versandkosten="950" bestellnummer="2021062115086"
                       shop="1" bestellnummerextshop="12345-etsy" versandkostenid="4"
    />
</dataset>
```


Die Testklasse die die Anweisungen ausführt und am ende vergleiche soll
[CODE lang="java" title="testklasse"]package abu.dao;
import static abu.dao.DBTestConnect.*;
import static org.junit.jupiter.api.Assertions.*;

import abu.datamodel.ProductCart;
import abu.dbutil.Database;
import abu.dbutil.DatabaseTest;
import org.dbunit.Assertion;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.dbunit.DBTestCase;
import org.dbunit.DatabaseUnitException;
import org.dbunit.operation.DatabaseOperation;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.*;
import java.util.ArrayList;

public class KundenBestellungDAOTest {
    PreparedStatement preparedStatement = null;

    @Before
    public void setUp() throws SQLException,  DatabaseUnitException, FileNotFoundException {
        //database.open();
        System.out.println("Testddd");
        IDataSet dataSetProdukt =
                new FlatXmlDataSetBuilder().build(new FileInputStream("/home/georg/IdeaProjects/abu_java/src/test/java/abu/dao/datasets/ProduktDataSet.xml"));
        try {
            DatabaseOperation.CLEAN_INSERT.execute(getConnection(), dataSetProdukt);
        } catch (DatabaseUnitException due) {
            throw due;
        } finally {
        }
    }

    @Test
    void loadShops() throws Exception{
        setUp();
        System.out.println("Test");
        String sqlProduktbestellung = "INSERT INTO Produktbestellung (datum_erzeugt, gesamtpreis, kunde, status, " +
                "versandkosten, bestellnummer, shop, bestellnummerextshop, versandkostenid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
        String sqlBestelleProdukt = "INSERT INTO BestelleProdukt (menge, preis, produktbestellung, produkt) VALUES (?, ?, ?, ?)";
        String sqlUpdateProdukt = "UPDATE Produkt SET anzahl = ? WHERE prodId = ?";
        String sqlProduktAnzahl = "SELECT anzahl FROM Produkt WHERE prodId = ?";

        try {
            getConnection().getConnection().setAutoCommit(false);
            int newOrderId = 0;
            int prodAnzahl = 0;
            String orderDate = "2021-06-21";
            int calcSummerySum = 6950;
            int kuId = 6;
            int shipping = 950;
            String bestelNummer = "2021062115086";
            int shopId = 1;
            String bestellnummerExtShop = "12345-etsy";
            int shippingId = 4;
            ArrayList<ProductCart> orderList = new ArrayList<>();
            orderList.add(new ProductCart(1, 1250, 2500, "Supercollier",    2, "CO1"));
            orderList.add(new ProductCart(2, 4450, 4450, "Kette3", 1, "HK2"));


            preparedStatement = getConnection().getConnection().prepareStatement(sqlProduktbestellung);
            preparedStatement.setString(1, orderDate);
            preparedStatement.setInt(2, calcSummerySum);
            preparedStatement.setInt(3, kuId);
            preparedStatement.setInt(4, 0);
            preparedStatement.setInt (5, shipping);
            preparedStatement.setString(6, bestelNummer);
            preparedStatement.setInt(7, shopId);
            preparedStatement.setString(8, bestellnummerExtShop);
            if(shippingId > 0)
                preparedStatement.setInt(9, shippingId);
            else
                preparedStatement.setNull(9, Types.INTEGER);

            preparedStatement.executeUpdate();
            ResultSet rs = preparedStatement.getGeneratedKeys();
            if(rs.next()) {
                newOrderId = rs.getInt(1);
            }

            for(ProductCart product : orderList){
                preparedStatement = getConnection().getConnection().prepareStatement(sqlBestelleProdukt);
                preparedStatement.setInt(1, product.getAnzahl());
                preparedStatement.setInt(2, product.getPreis());
                preparedStatement.setInt(3, newOrderId);
                preparedStatement.setInt(4, product.getProdId());
                preparedStatement.executeUpdate();

                preparedStatement = getConnection().getConnection().prepareStatement(sqlProduktAnzahl);
                preparedStatement.setInt(1, product.getProdId());
                preparedStatement.executeQuery();
                ResultSet resultSet = preparedStatement.executeQuery();
                while(resultSet.next()) {
                    prodAnzahl = resultSet.getInt(1);
                }

                int updateProdCount = prodAnzahl - product.getAnzahl();
                preparedStatement = getConnection().getConnection().prepareStatement(sqlUpdateProdukt);
                preparedStatement.setInt(1, updateProdCount);
                preparedStatement.setInt(2, product.getProdId());
                preparedStatement.executeUpdate();
            }
            getConnection().getConnection().commit();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        IDataSet databaseDataSet = getConnection().createDataSet();
        ITable produktTable = databaseDataSet.getTable("Produkt");
        ITable produktBestellungTable = databaseDataSet.getTable("Produktbestellung");
        ITable BestelleProduktable = databaseDataSet.getTable("BestelleProdukt");
        IDataSet expectedProduktDataSet = new FlatXmlDataSetBuilder().build(new File("/home/georg/IdeaProjects/abu_java/src/test/java/abu/dao/datasets/TestProduktDataSet.xml"));
        IDataSet expectedProduktbestellungDataSet = new FlatXmlDataSetBuilder().build(new File("/home/georg/IdeaProjects/abu_java/src/test/java/abu/dao/datasets/TestProduktbestellungDataSet.xml"));
        IDataSet expectedBestelleProduktDataSet = new FlatXmlDataSetBuilder().build(new File("/home/georg/IdeaProjects/abu_java/src/test/java/abu/dao/datasets/TestBestelleProduktDataSet.xml"));
        ITable expectedProduktTable = expectedProduktDataSet.getTable("Produkt");
        ITable expectedProduktbestellungTable = expectedProduktbestellungDataSet.getTable("Produktbestellung");
        ITable expectedBestelleProduktTable = expectedBestelleProduktDataSet.getTable("BestelleProdukt");
        Assertion.assertEquals(expectedProduktTable, produktTable);
        Assertion.assertEquals(expectedProduktbestellungTable, produktBestellungTable);
        Assertion.assertEquals(BestelleProduktable, expectedBestelleProduktTable);


    }

    public IDatabaseConnection getConnection(){
        return DBTestConnect.getConnection();
    }

}
[/CODE]

Die Fehlermeldung, wenn ich die Spalten die NULL sein sollen einfach weg lasse.


```
column count (table=Produktbestellung, expectedColCount=10, actualColCount=14) expected:<...hop, datum_erzeugt, []gesamtpreis, kunde, ...> but was:<...hop, datum_erzeugt, [datum_geliefert, datum_storniert, datum_versendet, datum_wideruf, ]gesamtpreis, kunde, ...>
Expected :[bestellnummer, bestellnummerextshop, datum_erzeugt, gesamtpreis, kunde, prodbestId, shop, status, versandkosten, versandkostenid]
Actual   :[bestellnummer, bestellnummerextshop, datum_erzeugt, datum_geliefert, datum_storniert, datum_versendet, datum_wideruf, gesamtpreis, kunde, prodbestId, shop, status, versandkosten, versandkostenid]
```


VG niesel


----------



## LimDul (25. Jun 2021)

Ok, dann baut dein Test die Tabelle falsch auf.

Was fehlt (an der Stelle kenne ich DB-Unit nicht) ist die Definition der Tabelle. Anscheinend wird deine Tabelle aus dem Insert-Dataset erzeugt. Wenn du da Elemente weglässt weiß DBUnit nicht, dass diese Spalten überhaupt exisitieren. Irgendwo fehlt dir anscheinend die Definition für DBUnit wie die Tabelle eigentlich aussehen soll.


----------



## nieselfriem (25. Jun 2021)

Nope das ist es nicht. Die Tabelle wird so erstellt wie erwartet. Die Tabellenname ist in 


```
<Produktbestellung....
```


----------



## kneitzel (25. Jun 2021)

Also ich denke doch, dass es das sein müsste. Denn das DataSet, das raus kommt, dem fehlen schlicht Felder.

Wenn alle Felder irgendwo beschrieben werden (also nicht immer null sind), dann könnte es evtl. ausreichen, dass man dem Builder noch etwas mehr setzt:
`IDataSet expectedProduktDataSet = new FlatXmlDataSetBuilder().setColumnSensing(true).build(...);`

Aber wenn da auch nicht alle Felder vorkommen, dann wäre es notwendig, die Metadaten einmal bekannt zu geben:
`IDataSet expectedProduktDataSet = new FlatXmlDataSetBuilder().setMetaDataSet(metaDataSet).build(...);`
(Edit: oder natürlich die DTD Variante!)

Das wären zumindest meine Ansätze.

Diesbezüglich auch einfach der Hinweis auf die Doku;





						DbUnit – Core Components
					






					dbunit.sourceforge.net
				





> Table metadata is deduced from the first row of each table by default, whereas it is possible to enable the _column sensing_ feature as described in differentcolumnnumber *Beware you may get a NoSuchColumnException if the first row of a table has one or more null values.* Because of that, this is highly recommended to use DTD. DbUnit will use the columns declared in the DTD as table metadata. DbUnit only support external system URI. The URI can be absolute or relative.
> Another way to cope with this problem is to use the ReplacementDataSet.



Edit: Die DTD variante ist natürlich ebenso möglich.


----------



## nieselfriem (25. Jun 2021)

LimDul hat gesagt.:


> Ok, dann baut dein Test die Tabelle falsch auf.
> 
> Was fehlt (an der Stelle kenne ich DB-Unit nicht) ist die Definition der Tabelle. Anscheinend wird deine Tabelle aus dem Insert-Dataset erzeugt. Wenn du da Elemente weglässt weiß DBUnit nicht, dass diese Spalten überhaupt exisitieren. Irgendwo fehlt dir anscheinend die Definition für DBUnit wie die Tabelle eigentlich aussehen soll.


Ich habe die Tabelle manuell erzeugt und diese liegt in ihrer Struktur leer da. ich hate die Frage erst falsch verstanden.


----------

