Introduksjon til DBUnit

1. Introduksjon

I denne veiledningen tar vi en titt på DBUnit, et enhetstestverktøy som brukes til testrelasjonell database interaksjoner i Java.

Vi får se hvordan det hjelper oss med å få databasen vår til en kjent tilstand og hevde mot en forventet tilstand.

2. Avhengigheter

Først kan vi legge til DBUnit i prosjektet vårt fra Maven Central ved å legge til dbunit avhengighet til vår pom.xml:

 org.dbunit dbunit 2.7.0 test 

Vi kan slå opp den nyeste versjonen på Maven Central.

3. Hello World Eksempel

Deretter la oss definere en databaseskjema:

schema.sql:

OPPRETT TABELL HVIS IKKE FINNER KLIENTER (`id` int AUTO_INCREMENT NOT NULL,` first_name` varchar (100) NOT NULL, `last_name` varchar (100) NOT NULL, PRIMARY KEY (` id`)); OPPRETT TABELL HVIS IKKE FUNNER VARER (`id` int AUTO_INCREMENT NOT NULL,` title` varchar (100) NOT NULL, `produsert` dato,` price` float, PRIMARY KEY (`id`)); 

3.1. Definere innledende databasens innhold

DBUnit lar oss definere og laste testdatasettet vårt på en enkel måteerklærende måte.

Vi definerer hver tabellrad med ett XML-element, der taggenavnet er et tabellnavn, og attributtnavn og verdier tilordnes henholdsvis kolonnenavn og verdier. Radedataene kan opprettes for flere tabeller. Vi må implementere getDataSet () Metode av DataSourceBasedDBTestCase for å definere det opprinnelige datasettet, hvor vi kan bruke FlatXmlDataSetBuilder å henvise til XML-filen vår:

data.xml:

3.2. Initialisere databasetilkoblingen og skjemaet

Nå som vi har skjemaet vårt, må vi initialisere databasen.

Vi må utvide DataSourceBasedDBTestCase klasse og initialisere databaseskjemaet i getDataSource () metode:

DataSourceDBUnitTest.java:

offentlig klasse DataSourceDBUnitTest utvider DataSourceBasedDBTestCase {@Override-beskyttet DataSource getDataSource () {JdbcDataSource dataSource = ny JdbcDataSource (); dataSource.setURL ("jdbc: h2: mem: standard; DB_CLOSE_DELAY = -1; init = runskript fra 'classpath: schema.sql'"); dataSource.setUser ("sa"); dataSource.setPassword ("sa"); returner datakilde; } @ Override-beskyttet IDataSet getDataSet () kaster unntak {returner nye FlatXmlDataSetBuilder (). Build (getClass (). GetClassLoader () .getResourceAsStream ("data.xml")); }}

Her sendte vi en SQL-fil til en H2-minne-database i tilkoblingsstrengen. Hvis vi ønsker å teste på andre databaser, må vi gi vår tilpassede implementering for den.

Husk det, i vårt eksempel, DBUnit vil initialisere databasen på nytt med de gitte testdataene før hver testmetode kjøres.

Det er flere måter å konfigurere dette via SetUpOperation og TearDownOperation:

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

De FORFRISKE drift, ber DBUnit om å oppdatere alle dataene. Dette vil sikre at alle cacher blir ryddet, og enhetstesten vår får ingen innflytelse fra en annen enhetstest. De SLETTE ALLE operasjonen sørger for at alle data blir fjernet på slutten av hver enhetstest. I vårt tilfelle forteller vi DBUnit at under oppsett, ved hjelp av getSetUpOperation metodeimplementering vil vi oppdatere alle cacher. Til slutt ber vi DBUnit om å fjerne all data under nedrivningsoperasjonen ved hjelp av getTearDownOperation metodeimplementering.

3.3. Sammenligning av den forventede staten og den faktiske staten

La oss nå undersøke vår faktiske testtilfelle. For denne første testen holder vi det enkelt - vi laster inn vårt forventede datasett og sammenligner det med datasettet hentet fra DB-tilkoblingen:

@Test offentlig ugyldig givenDataSetEmptySchema_whenDataSetCreated_thenTablesAreEqual () kaster unntak {IDataSet expectDataSet = getDataSet (); ITable expectTable = expectDataSet.getTable ("CLIENTS"); IDataSet databaseDataSet = getConnection (). CreateDataSet (); ITable actualTable = databaseDataSet.getTable ("KLIENTER"); assertEquals (forventet tabell, faktisk tabell); }

4. Dyp dykk inn i Påstander

I forrige avsnitt så vi et grunnleggende eksempel på å sammenligne det faktiske innholdet i en tabell med et forventet datasett. Nå skal vi oppdage DBUnits støtte for å tilpasse datapåstander.

4.1. Påstå med en SQL-spørring

En enkel måte å kontrollere den faktiske tilstanden er med et SQL-spørsmål.

I dette eksemplet setter vi inn en ny post i CLIENTS-tabellen, og verifiserer innholdet i den nylig opprettede raden. Vi definerte forventet produksjon i en egen XML-fil, og hentet den faktiske radverdien med et SQL-spørsmål:

@Test offentlig ugyldig givenDataSet_whenInsert_thenTableHasNewClient () kaster Unntak {try (InputStream er = getClass (). GetClassLoader (). GetResourceAsStream ("dbunit / forventet-bruker.xml")) {IDataSet forventet DataSet = ny FlatXmlData.) () ITable expectTable = expectDataSet.getTable ("CLIENTS"); Connection conn = getDataSource (). GetConnection (); conn.createStatement () .executeUpdate ("INSERT IN CLIENTS (first_name, last_name) VALUES ('John', 'Jansen')"); ITable actualData = getConnection () .createQueryTable ("result_name", "SELECT * FROM CLIENTS WHERE last_name =" Jansen ""); assertEqualsIgnoreCols (forventet tabell, faktisk data, ny streng [] {"id"}); }}

De getConnection () metoden for DBTestCase forfedre klasse returnerer en DBUnit-spesifikk representasjon av datakildeforbindelsen (en IDatabaseConnection forekomst). De createQueryTable () metoden for IDatabaseConnection kan brukes til å hente faktiske data fra databasen, til sammenligning med forventet databasetilstand, ved hjelp av Assertion.assertEquals () metode. SQL-spørringen ble sendt videre createQueryTable () er spørringen vi vil teste. Det returnerer a Bord eksempel som vi bruker for å hevde oss.

4.2. Ignorer kolonner

Noen ganger i databasetester vil vi ignorere noen kolonner i de faktiske tabellene. Dette er vanligvis automatisk genererte verdier som vi ikke kan kontrollere strengt, for eksempel genererte primærnøkler eller nåværende tidsstempler.

Vi kunne gjøre dette ved å utelate kolonnene fra SELECT-leddene i SQL-spørringene, men DBUnit gir et mer praktisk verktøy for å oppnå dette. Med de statiske metodene til DefaultColumnFilter klasse kan vi lage en ny ITable forekomst fra en eksisterende ved å ekskludere noen av kolonnene, som vist her:

@Test offentlig tomrom gittDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced () kaster Unntak {Connection connection = tester.getConnection (). GetConnection (); Streng [] ekskludertKolonner = {"id", "produsert"}; prøv (InputStream er = getClass (). getClassLoader () .getResourceAsStream ("dbunit / forventet-ignorering-registrert_at.xml")) {IDataSet forventetDataSett = ny FlatXmlDataSetBuilder (). bygg (er); ITable expectTable = ekskludertColumnTable (forventetDataSet.getTable ("ITEMS"), ekskludertKolonner); connection.createStatement () .executeUpdate ("INSERT IN ITEMS (title, price, produced) VALUES ('Necklace', 199.99, now ())"); IDataSet databaseDataSet = tester.getConnection (). CreateDataSet (); ITable actualTable = ekskludert Kolonnetabell (databaseDataSet.getTable ("ITEMS"), ekskludert Kolonner); assertEquals (forventet tabell, faktisk tabell); }}

4.3. Undersøke flere feil

Hvis DBUnit finner en feil verdi, så kaster den umiddelbart en Påstand Feil.

I spesifikke tilfeller kan vi bruke DiffCollectingFailureHandler klasse, som vi kan overføre til Assertion.assertEquals () metode som et tredje argument.

Denne feilbehandleren vil samle alle feil i stedet for å stoppe på den første, noe som betyr at de Assertion.assertEquals () metoden vil alltid lykkes hvis vi bruker DiffCollectingFailureHandler. Derfor må vi programmatisk sjekke om behandleren fant noen feil:

@Test offentlig ugyldig givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​() kaster unntak {try (InputStream er = getClass (). GetClassLoader () .getResourceAsStream ("dbunit / forventet-flere feil) ); ITable expectTable = expectDataSet.getTable ("ITEMS"); Connection conn = getDataSource (). GetConnection (); DiffCollectingFailureHandler collectHandler = ny DiffCollectingFailureHandler (); conn.createStatement () .executeUpdate ("INSERT IN TO ITEMS (title, price) VALUES ('Battery', '1000000')"); ITable actualData = getConnection (). CreateDataSet (). GetTable ("ITEMS"); assertEquals (forventet tabell, faktisk data, samlehandler); if (! collectorHandler.getDiffList (). isEmpty ()) {String message = (String) collectHandler.getDiffList () .stream () .map (d -> formatDifference ((Difference) d)) .collect (joining ("\ n ")); logger.error (() -> melding); }}} privat statisk strengformatForskjell (forskjell diff) {returnerer "forventet verdi i" + diff.getExpectedTable () .getTableMetaData () .getTableName () + "." + diff.getColumnName () + "rad" + diff.getRowIndex () + ":" + diff.getExpectedValue () + ", men var:" + diff.getActualValue (); }

Videre gir behandleren feilene i form av Forskjell forekomster, som lar oss formatere feilene.

Etter å ha kjørt testen får vi en formatert rapport:

java.lang.AssertionError: forventet verdi i ITEMS. pris rad 5: 199.99, men var: 1000000.0 forventet verdi i ITEMS. produsert rad 5: 2019-03-23, men var: null forventet verdi i ITEMS. tittel rad 5: Halskjede , men var: Batteri på com.baeldung.dbunit.DataSourceDBUnitTest.givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​(DataSourceDBUnitTest.java:91)

Det er viktig å legge merke til at vi på dette tidspunktet forventet at den nye varen ville ha en pris på 199,99, men den var 1000000,0. Så ser vi at produksjonsdatoen skal være 2019-03-23, men til slutt var den null. Til slutt var det forventede elementet et halskjede, og i stedet fikk vi et batteri.

5. Konklusjon

I denne artikkelen så vi hvordan DBUnit gir en deklarativ måte å definere testdata på til test datatilgangslag av Java-applikasjoner.

Som alltid er hele kildekoden for eksemplene tilgjengelig på GitHub.


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