Uvod u DBUnit

1. Uvod

U ovom uputstvu ćemo pogledati DBUnit, alat za jedinično testiranje koji se nekada koristio testinterakcije relacijske baze podataka u Java.

Vidjet ćemo kako će nam pomoći da našu bazu podataka dovedemo u poznato stanje i utvrdimo protiv očekivanog stanja.

2. Ovisnosti

Prvo, možemo dodati DBUnit u naš projekt iz Maven Central dodavanjem dbunit ovisnost o našoj pom.xml:

 org.dbunit dbunit 2.7.0 test 

Najnoviju verziju možemo potražiti na Maven Central.

3. Primjer Hello World

Dalje, definirajmo a shema baze podataka:

shema.sql:

STVORI TABELU AKO NE POSTOJI KLIJENTI (`id` int AUTO_INCREMENT NOT NULL,` first_name` varchar (100) NOT NULL, `last_name` varchar (100) NOT NULL, PRIMARNI KLJUČ (` id`)); STVORI TABELU AKO NE POSTOJI STAVKE (`id` int AUTO_INCREMENT NOT NULL,` title` varchar (100) NOT NULL, `proizvedeni` datum,` cijena` pluta, PRIMARNI KLJUČ (`id`)); 

3.1. Definiranje početnog sadržaja baze podataka

DBUnit nam omogućuje definiranje i učitavanje našeg testnog skupa podataka na jednostavan načindeklarativni način.

Svaki red tablice definiramo jednim XML elementom, pri čemu je naziv oznake naziv tablice, a nazivi i vrijednosti atributa mapiraju se u nazive stupaca i vrijednosti. Podaci retka mogu se stvoriti za više tablica. Moramo provesti getDataSet () metoda DataSourceBasedDBTestCase za definiranje početnog skupa podataka, gdje možemo koristiti FlatXmlDataSetBuilder kako bi se pozvali na našu XML datoteku:

data.xml:

3.2. Inicijalizacija veze i sheme baze podataka

Sad kad smo dobili našu shemu, moramo inicijalizirati našu bazu podataka.

Moramo produžiti DataSourceBasedDBTestCase klase i inicijalizira shemu baze podataka u svojoj getDataSource () metoda:

DataSourceDBUnitTest.java:

javna klasa DataSourceDBUnitTest proširuje DataSourceBasedDBTestCase {@Override protected DataSource getDataSource () {JdbcDataSource dataSource = new JdbcDataSource (); dataSource.setURL ("jdbc: h2: mem: default; DB_CLOSE_DELAY = -1; init = runscript iz 'classpath: schema.sql'"); dataSource.setUser ("sa"); dataSource.setPassword ("sa"); vratiti dataSource; } @Override protected IDataSet getDataSet () baca iznimku {return new FlatXmlDataSetBuilder (). Build (getClass (). GetClassLoader () .getResourceAsStream ("data.xml")); }}

Ovdje smo proslijedili SQL datoteku u H2 bazu podataka u memoriji u njenom nizu veze. Ako želimo testirati na drugim bazama podataka, morat ćemo pružiti prilagođenu implementaciju za nju.

Imajte na umu da, u našem primjeru, DBUnit će reinicijalizirati bazu podataka s danim testnim podacima prije svakog izvođenja metode ispitivanja.

Postoji više načina za konfiguriranje putem dobitiSetUpOperation i dobitiTearDownOperation:

@Override protected DatabaseOperation getSetUpOperation () {return DatabaseOperation.REFRESH; } @Override protected DatabaseOperation getTearDownOperation () {return DatabaseOperation.DELETE_ALL; }

The OSVJEŽITI operacija, govori DBUnit-u da osvježi sve svoje podatke. To će osigurati da se sve predmemorije očiste i da naš jedinični test ne utječe na drugi jedinstveni test. The IZBRISATI SVE operacija osigurava uklanjanje svih podataka na kraju svakog jediničnog testa. U našem slučaju kažemo DBUnit-u da će tijekom postavljanja pomoću getSetUpOperation implementacije metode osvježit ćemo sve predmemorije. Na kraju, kažemo DBUnit-u da ukloni sve podatke tijekom operacije uklanjanja pomoću getTearDownOperation provedba metode.

3.3. Usporedba očekivane države i stvarne države

Sada, ispitajmo naš stvarni testni slučaj. Za ovaj prvi test pojednostavit ćemo - učitat ćemo očekivani skup podataka i usporediti ga sa skupom podataka dohvaćenom iz naše DB veze:

@Test javna praznina givenDataSetEmptySchema_whenDataSetCreated_thenTablesAreEqual () baca izuzetak {IDataSet očekujeDataSet = getDataSet (); ITable očekujeTable = očekuje seDataSet.getTable ("KLIJENTI"); IDataSet databaseDataSet = getConnection (). CreateDataSet (); ITable actualTable = databaseDataSet.getTable ("KLIJENTI"); assertEquals (očekivanaTabela, stvarnaTablica); }

4. Duboko zaronite Tvrdnje

U prethodnom smo odjeljku vidjeli osnovni primjer usporedbe stvarnog sadržaja tablice s očekivanim skupom podataka. Sada ćemo otkriti podršku DBUnit-a za prilagođavanje tvrdnji podataka.

4.1. Utvrđivanje pomoću SQL upita

Izravan način provjere stvarnog stanja je pomoću SQL upita.

U ovom ćemo primjeru umetnuti novi zapis u tablicu KLIJENTI, a zatim provjeriti sadržaj novostvorenog retka. Očekivani izlaz definirali smo u zasebna XML datoteka, i izvadio stvarnu vrijednost retka SQL upitom:

@Test public void givenDataSet_whenInsert_thenTableHasNewClient () baca izuzetak {try (InputStream is = getClass (). GetClassLoader (). GetResourceAsStream ("dbunit / očekuje-korisnik.xml")) {IDataSetta newDa ITable očekujeTable = očekuje seDataSet.getTable ("KLIJENTI"); Veza 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 (očekivanaTabela, stvarniData, novi String [] {"id"}); }}

The getConnection () metoda DBTestCase predak klasa vraća DBUnit-specifičnu reprezentaciju veze izvora podataka (an IDatabaseConnection primjer). The createQueryTable () metoda IDatabaseConnection može se koristiti za dohvaćanje stvarnih podataka iz baze podataka, za usporedbu s očekivanim stanjem baze podataka, koristeći Assertion.assertEquals () metoda. SQL upit proslijeđen createQueryTable () je upit koji želimo testirati. Vraća a Stol primjer kojim se koristimo za potvrđivanje.

4.2. Zanemarivanje stupaca

Ponekad u testovima baze podataka želimo zanemariti neke stupce stvarnih tablica. To su obično automatski generirane vrijednosti koje, primjerice, ne možemo strogo kontrolirati generirani primarni ključevi ili trenutne vremenske oznake.

To bismo mogli učiniti izostavljanjem stupaca iz klauzula SELECT u SQL upitima, ali DBUnit pruža prikladniji uslužni program za postizanje toga. Sa statičkim metodama DefaultColumnFilter razreda možemo stvoriti novi ITable primjer iz postojećeg izuzimanjem nekih stupaca, kao što je prikazano ovdje:

@Test javna praznina givenDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced () baca izuzetak {Connection connection = tester.getConnection (). GetConnection (); Niz [] excluColumns = {"id", "proizveden"}; probajte (InputStream je = getClass (). getClassLoader () .getResourceAsStream ("dbunit / očekivano-ignoriranje-registriran_at.xml")) {IDataSet očekujeDataSet = novi FlatXmlDataSetBuilder (). build (is); ITable očekivanaTabela = disabledColumnsTable (očekuje seDataSet.getTable ("ITEMS"), excluColumns); connection.createStatement () .executeUpdate ("Umetni u stavke (naslov, cijena, proizvedeno) VRIJEDNOSTI ('Ogrlica', 199,99, sada ())"); IDataSet databaseDataSet = tester.getConnection (). CreateDataSet (); ITable actualTable = disabledColumnsTable (databaseDataSet.getTable ("ITEMS"), excluColumns); assertEquals (očekivanaTabela, stvarnaTablica); }}

4.3. Istraživanje višestrukih kvarova

Ako DBUnit pronađe netočnu vrijednost, a zatim odmah baca znak AssertionError.

U određenim slučajevima možemo koristiti DiffCollectingFailureHandler klase, koju možemo prenijeti na Assertion.assertEquals () metoda kao treći argument.

Ovaj rukovatelj kvarom prikupit će sve kvarove, umjesto da se zaustavi na prvom, što znači da the Assertion.assertEquals () metoda uvijek će uspjeti ako koristimo DiffCollectingFailureHandler. Stoga ćemo morati programski provjeriti je li voditelj pronašao greške:

@Test public void givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​() baca Iznimka {probati (InputStream je = getClass (). GetClassLoader () .getResourceAsStream ( "dbunit / Očekuje-više-failures.xml")) {IDataSet expectedDataSet = new FlatXmlDataSetBuilder (). Graditi (je ); ITable očekujeTabela = očekuje seDataSet.getTable ("ITEMS"); Veza conn = getDataSource (). GetConnection (); DiffCollectingFailureHandler prikupljanjeHandler = novo DiffCollectingFailureHandler (); conn.createStatement () .executeUpdate ("INSERT IN TO ITEMS (title, price) VALUES ('Battery', '1000000')"); ITable actualData = getConnection (). CreateDataSet (). GetTable ("ITEMS"); assertEquals (očekivanaTabela, stvarniData, prikupljanjeHandler); if (! prikupljanjeHandler.getDiffList (). isEmpty ()) {String message = (String) prikupljanjeHandler.getDiffList () .stream () .map (d -> formatDifference ((Difference) d)) .collect (spajanje ("\ n ")); logger.error (() -> poruka); }}} privatni statički string formatDifference (Difference diff) {return "očekivana vrijednost u" + diff.getExpectedTable () .getTableMetaData () .getTableName () + "." + diff.getColumnName () + "row" + diff.getRowIndex () + ":" + diff.getExpectedValue () + ", ali je bio:" + diff.getActualValue (); }

Nadalje, rukovatelj pruža kvarove u obliku Razlika instanci, što nam omogućuje oblikovanje pogrešaka.

Nakon pokretanja testa dobivamo formatirano izvješće:

java.lang.AssertionError: očekivana vrijednost u retku ITEMS.price 5: 199,99, ali bila je: 1000000,0 očekivana vrijednost u ITEMS.proizvedena u retku 5: 2019-03-23, ali bila je: nula očekivana vrijednost u ITEMS.title reda 5: Ogrlica , ali bio je: Baterija na com.baeldung.dbunit.DataSourceDBUnitTest.givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​(DataSourceDBUnitTest.java:91)

Važno je primijetiti da smo u ovom trenutku očekivali da će nova stavka imati cijenu od 199,99, ali je iznosila 1000000,0. Tada vidimo da će datum proizvodnje biti 23. ožujka 2019., ali na kraju je bio ništavan. Napokon, očekivani predmet bila je Ogrlica, a umjesto nje dobili smo bateriju.

5. Zaključak

U ovom smo članku vidjeli kako DBUnit pruža a deklarativni način definiranja testnih podataka do testirati slojeve pristupa podacima Java aplikacija.

Kao i uvijek, puni izvorni kod za primjere dostupan je na GitHubu.