Úvod do DBUnit

1. Úvod

V tomto výučbe sa pozrieme na DBUnit, nástroj na testovanie jednotiek, ktorý sa zvykol používať testinterakcie relačnej databázy v Java.

Uvidíme, ako nám to pomôže dostať našu databázu do známeho stavu a presadiť sa proti očakávanému stavu.

2. Závislosti

Najskôr môžeme do nášho projektu pridať DBUnit z Maven Central pridaním dbunit závislosť na našom pom.xml:

 test org.dbunit dbunit 2.7.0 

Najnovšiu verziu môžeme vyhľadať v Maven Central.

3. Ahoj svet príklad

Ďalej definujeme a schéma databázy:

schema.sql:

VYTVORIŤ TABUĽKU, AK NEEXISTUJE KLIENTI (`id 'int AUTO_INCREMENT NIE NULL,` first_name` varchar (100) NIE NULL, `last_name` varchar (100) NIE NULL, PRIMÁRNY KLÍČ (` id`)); VYTVORIŤ TABUĽKU, AK NEEXISTUJÚ POLOŽKY (`id` int AUTO_INCREMENT NOT NULL,` title` varchar (100) NOT NULL, `vyrobené 'dátum,` price` float, PRIMARY KEY (`id`)); 

3.1. Definovanie počiatočného obsahu databázy

DBUnit nám umožňuje jednoducho definovať a načítať náš testovací súbor údajovdeklaratívnym spôsobom.

Každý riadok tabuľky definujeme jedným prvkom XML, kde názov značky je názov tabuľky a názvy atribútov a hodnoty sa mapujú na názvy stĺpcov a hodnoty. Údaje o riadkoch je možné vytvoriť pre viac tabuliek. Musíme implementovať getDataSet () metóda DataSourceBasedDBTestCase definovať počiatočný súbor údajov, kde môžeme použiť FlatXmlDataSetBuilder odkázať na náš súbor XML:

data.xml:

3.2. Inicializuje sa databázové pripojenie a schéma

Teraz, keď máme našu schému, musíme inicializovať našu databázu.

Musíme predĺžiť DataSourceBasedDBTestCase triedy a inicializovať databázovú schému v jej getDataSource () metóda:

DataSourceDBUnitTest.java:

verejná trieda DataSourceDBUnitTest rozširuje DataSourceBasedDBTestCase {@Override chránený DataSource getDataSource () {JdbcDataSource dataSource = nový JdbcDataSource (); dataSource.setURL ("jdbc: h2: mem: default; DB_CLOSE_DELAY = -1; init = runscript z 'classpath: schema.sql'"); dataSource.setUser ("sa"); dataSource.setPassword ("sa"); vrátiť dátový zdroj; } @Override chránený IDataSet getDataSet () vyvolá výnimku {return new FlatXmlDataSetBuilder (). Build (getClass (). GetClassLoader () .getResourceAsStream ("data.xml")); }}

Tu sme odovzdali súbor SQL do databázy H2 v pamäti v jej pripojovacom reťazci. Ak chceme testovať na iných databázach, budeme musieť poskytnúť vlastnú implementáciu.

Pamätajte na to, v našom príklade Pred vykonaním každej testovacej metódy DBUnit znova inicializuje databázu s danými testovacími údajmi.

Existuje niekoľko spôsobov, ako to nakonfigurovať pomocou dostaťSetUpOperation a dostaťTearDownOperation:

@Override chránený DatabaseOperation getSetUpOperation () {návrat DatabaseOperation.REFRESH; } @Override chránená DatabaseOperation getTearDownOperation () {návrat DatabaseOperation.DELETE_ALL; }

The OBNOVIŤ operácia, povie DBUnit, aby obnovila všetky svoje údaje. To zaistí, že všetky pamäte cache sú vymazané a náš test jednotky nebude mať žiadny vplyv z iného testu jednotky. The VYMAZAŤ VŠETKO Táto operácia zaisťuje odstránenie všetkých údajov na konci každého testu jednotky. V našom prípade hovoríme DBUnit, že počas nastavovania pomocou getSetUpOperation spôsob implementácie obnovíme všetky kešky. Nakoniec povieme DBUnit, aby odstránil všetky dáta počas operácie roztrhnutia pomocou getTearDownOperation implementácia metódy.

3.3. Porovnanie očakávaného a skutočného stavu

Teraz sa pozrime na náš skutočný testovací prípad. Pri tomto prvom teste to zjednodušíme - načítame náš očakávaný súbor údajov a porovnáme ho so súborom údajov získaným z nášho pripojenia DB:

@Test public void givenDataSetEmptySchema_whenDataSetCreated_thenTablesAreEqual () vyvolá výnimku {IDataSet expectDataSet = getDataSet (); ITable expectTable = expectDataSet.getTable ("CLIENTS"); IDataSet databaseDataSet = getConnection (). CreateDataSet (); ITable actualTable = databaseDataSet.getTable ("KLIENTI"); assertEquals (expectTable, actualTable); }

4. Deep Dive Into Tvrdenia

V predchádzajúcej časti sme videli základný príklad porovnania skutočného obsahu tabuľky s očakávanou množinou údajov. Teraz objavíme podporu nástroja DBUnit na prispôsobenie údajov.

4.1. Tvrdenie pomocou dotazu SQL

Priamy spôsob kontroly skutočného stavu je pomocou dotazu SQL.

V tomto príklade vložíme nový záznam do tabuľky KLIENTI a potom overíme obsah novovytvoreného riadku. Očakávaný výstup sme definovali v samostatný súbor XMLa extrahovali skutočnú hodnotu riadku pomocou dotazu SQL:

@Test public void givenDataSet_whenInsert_thenTableHasNewClient () vyvolá výnimku {try (InputStream je = getClass (). GetClassLoader (). GetResourceAsStream ("dbunit / expect-user.xml")) {IDataSet expectDataSet =) FlatBmlDataSet = nový FlatXmlDataSet = nový FlatXmlDataSet ITable expectTable = expectDataSet.getTable ("CLIENTS"); Pripojenie conn = getDataSource (). GetConnection (); conn.createStatement () .executeUpdate ("INSERT INTO CLIENTS (first_name, last_name) VALUES ('John', 'Jansen')"); ITable actualData = getConnection () .createQueryTable ("result_name", "SELECT * FROM CLIENTS WHERE last_name =" Jansen ""); assertEqualsIgnoreCols (expectTable, actualData, nový reťazec [] {"id"}); }}

The getConnection () metóda DBTestCase trieda ancestor vráti reprezentáciu pripojenia zdroja údajov špecifickú pre DBUnit (an IDatabaseConnection inštancia). The createQueryTable () metóda IDatabaseConnection možno použiť na získanie aktuálnych údajov z databázy, pre porovnanie s očakávaným stavom databázy pomocou Assertion.assertEquals () metóda. Dotaz SQL bol odovzdaný do createQueryTable () je dopyt, ktorý chceme testovať. Vracia a Tabuľka príklad, ktorý používame na presadenie sa.

4.2. Ignorovanie stĺpcov

Niekedy v testoch databázy chceme ignorovať niektoré stĺpce skutočných tabuliek. Zvyčajne ide o automaticky generované hodnoty, ktoré nemôžeme striktne kontrolovať generované primárne kľúče alebo aktuálne časové značky.

Mohli by sme to urobiť vynechaním stĺpcov z klauzúl SELECT v dotazoch SQL, ale DBUnit poskytuje pohodlnejšiu pomôcku na dosiahnutie tohto cieľa. So statickými metódami DefaultColumnFilter triedy môžeme vytvoriť nový ITable napríklad z existujúceho vylúčením niektorých stĺpcov, ako je zobrazené tu:

@Test public void givenDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced () vyvolá výnimku {Connection connection = tester.getConnection (). GetConnection (); Reťazec [] vylúčenéColumns = {"id", "vyrobené"}; try (InputStream is = getClass (). getClassLoader () .getResourceAsStream ("dbunit / expect-ignoring-registered_at.xml")) {IDataSet expectDataSet = new FlatXmlDataSetBuilder (). build (is); ITable expectTable = vylúčenéColumnsTable (expectDataSet.getTable ("ITEMS"), vylúčenéColumns); connection.createStatement () .executeUpdate ("INSERT INTO ITEMS (názov, cena, vyrobené) HODNOTY ('Náhrdelník', 199,99, teraz ())"); IDataSet databaseDataSet = tester.getConnection (). CreateDataSet (); ITable actualTable = vylúčené stĺpce (DatabaseDataSet.getTable ("ITEMS"), vylúčené stĺpce); assertEquals (expectTable, actualTable); }}

4.3. Vyšetrovanie viacerých zlyhaní

Ak DBUnit nájde nesprávnu hodnotu, potom okamžite hodí AssertionError.

V konkrétnych prípadoch môžeme použiť DiffCollectingFailureHandler triedy, ktorú môžeme odovzdať do Assertion.assertEquals () metóda ako tretí argument.

Tento obslužný program zlyhaní zhromaždí všetky zlyhania namiesto toho, aby sa zastavil na prvom, to znamená the Assertion.assertEquals () metóda bude vždy úspešná, ak použijeme DiffCollectingFailureHandler. Preto budeme musieť programovo skontrolovať, či obslužný program našiel nejaké chyby:

@Test public void givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​() vyvolá výnimku {try (InputStream je = getClass (). GetClassLoader () .getResourceAsStream ("dbunit / expect-multiple-failures.xml")) {IDataSetDB = ); ITable expectTable = expectDataSet.getTable ("ITEMS"); Pripojenie conn = getDataSource (). GetConnection (); DiffCollectingFailureHandler collectHandler = nový DiffCollectingFailureHandler (); conn.createStatement () .executeUpdate ("INSERT INTO ITEMS (title, price) VALUES ('Battery', '1000000')"); ITable actualData = getConnection (). CreateDataSet (). GetTable ("ITEMS"); assertEquals (expectTable, actualData, collectHandler); if (! collectHandler.getDiffList (). isEmpty ()) {String message = (String) collectHandler.getDiffList () .stream () .map (d -> formatDifference ((Difference) d)) .collect (joining ("\ n ")); logger.error (() -> správa); }}} private static String formatDifference (Difference diff) {return "očakávaná hodnota v" + diff.getExectedTable () .getTableMetaData () .getTableName () + "." + diff.getColumnName () + "riadok" + diff.getRowIndex () + ":" + diff.getExposedValue () + ", ale bolo:" + diff.getActualValue (); }

Ďalej obslužný program poskytuje poruchy vo forme Rozdiel inštancie, čo nám umožňuje formátovať chyby.

Po vykonaní testu dostaneme formátovanú správu:

java.lang.AssertionError: očakávaná hodnota v ITEMS.cena riadok 5: 199,99, ale bola: 10 000 000,0 očakávaná hodnota v ITEMS. vyrobený riadok 5: 2019-03-23, ale bola: nulová očakávaná hodnota v ITEMS.title riadok 5: náhrdelník , ale bolo: Batéria na adrese com.baeldung.dbunit.DataSourceDBUnitTest.givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​(DataSourceDBUnitTest.java:91)

Je dôležité si uvedomiť, že v tomto okamihu sme očakávali, že nová položka bude mať cenu 199,99, ale bola to 10 000 000,0. Potom vidíme, že dátum výroby bude 23. 3. 2019, ale nakoniec bol nulový. Nakoniec očakávanou položkou bol Náhrdelník a namiesto toho sme dostali Batériu.

5. Záver

V tomto článku sme videli, ako poskytuje DBUnit a deklaratívny spôsob definovania testovacích údajov do otestujte vrstvy prístupu k údajom aplikácií Java.

Úplný zdrojový kód príkladov je ako vždy k dispozícii na serveri GitHub.


$config[zx-auto] not found$config[zx-overlay] not found