Inleiding tot DBUnit

1. Inleiding

In deze tutorial kijken we naar DBUnit, een tool voor het testen van eenheden testrelationele database-interacties in Java.

We zullen zien hoe het ons helpt om onze database in een bekende staat te krijgen en te beweren tegen een verwachte staat.

2. Afhankelijkheden

Ten eerste kunnen we DBUnit aan ons project toevoegen vanuit Maven Central door het dbunit afhankelijkheid van onze pom.xml:

 org.dbunit dbunit 2.7.0 test 

We kunnen de meest recente versie op Maven Central opzoeken.

3. Hallo wereld voorbeeld

Laten we vervolgens een databaseschema:

schema.sql:

MAAK EEN TABEL ALS ER GEEN KLANTEN BESTAAN (`id` int AUTO_INCREMENT NOT NULL,` first_name` varchar (100) NOT NULL, `last_name` varchar (100) NOT NULL, PRIMARY KEY (` id`)); MAAK EEN TABEL ALS ER GEEN ITEMS BESTAAN (`id` int AUTO_INCREMENT NOT NULL,` title` varchar (100) NOT NULL, `geproduceerd` datum,` prijs` float, PRIMAIRE SLEUTEL (`id`)); 

3.1. De initiële database-inhoud definiëren

Met DBUnit kunnen we onze testdataset definiëren en laden in een eenvoudigdeclaratieve manier.

We definiëren elke tabelrij met één XML-element, waarbij de tagnaam een ​​tabelnaam is, en kenmerknamen en waarden worden toegewezen aan respectievelijk kolomnamen en waarden. De rijgegevens kunnen voor meerdere tabellen worden gemaakt. We moeten het getDataSet () methode van DataSourceBasedDBTestCase om de initiële dataset te definiëren, waar we de FlatXmlDataSetBuilder om naar ons XML-bestand te verwijzen:

data.xml:

3.2. Initialiseren van de databaseverbinding en het schema

Nu we ons schema hebben, moeten we onze database initialiseren.

We moeten het DataSourceBasedDBTestCase class en initialiseer het databaseschema in zijn getDataSource () methode:

DataSourceDBUnitTest.java:

openbare klasse DataSourceDBUnitTest breidt DataSourceBasedDBTestCase uit {@Override beschermde DataSource getDataSource () {JdbcDataSource dataSource = nieuwe JdbcDataSource (); dataSource.setURL ("jdbc: h2: mem: default; DB_CLOSE_DELAY = -1; init = runscript van 'classpath: schema.sql'"); dataSource.setUser ("sa"); dataSource.setPassword ("sa"); retourneer dataSource; } @Override beschermde IDataSet getDataSet () gooit uitzondering {retourneer nieuwe FlatXmlDataSetBuilder (). Build (getClass (). GetClassLoader () .getResourceAsStream ("data.xml")); }}

Hier hebben we een SQL-bestand doorgegeven aan een H2 in-memory-database in de verbindingsreeks. Als we op andere databases willen testen, moeten we hiervoor onze aangepaste implementatie leveren.

Houd daar rekening mee, in ons voorbeeld DBUnit initialiseert de database opnieuw met de opgegeven testgegevens voordat elke testmethode wordt uitgevoerd.

Er zijn meerdere manieren om dit te configureren via krijgenSetUpOperation en krijgenTearDownOperation:

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

De VERFRISSEN operatie, vertelt DBUnit om al zijn gegevens te vernieuwen. Dit zorgt ervoor dat alle caches worden gewist en dat onze unit-test geen invloed krijgt van een andere unit-test. De VERWIJDER ALLES operatie zorgt ervoor dat alle gegevens worden verwijderd aan het einde van elke unit-test. In ons geval vertellen we DBUnit dat tijdens het instellen de getSetUpOperation methode implementatie zullen we alle caches vernieuwen. Ten slotte vertellen we DBUnit om alle gegevens te verwijderen tijdens de demontagebewerking met behulp van de getTearDownOperation methode implementatie.

3.3. Vergelijking van de verwachte staat en de werkelijke staat

Laten we nu onze eigenlijke testcase bekijken. Voor deze eerste test houden we het simpel: we laden onze verwachte dataset en vergelijken deze met de dataset die is opgehaald uit onze DB-verbinding:

@Test openbare leegte gegevenDataSetEmptySchema_whenDataSetCreated_thenTablesAreEqual () gooit uitzondering {IDataSet verwachteDataSet = getDataSet (); ITable verwachteTable = verwachteDataSet.getTable ("KLANTEN"); IDataSet databaseDataSet = getConnection (). CreateDataSet (); ITable actualTable = databaseDataSet.getTable ("KLANTEN"); assertEquals (verwachteTable, actualTable); }

4. Duik diep in Beweringen

In de vorige sectie hebben we een eenvoudig voorbeeld gezien van het vergelijken van de werkelijke inhoud van een tabel met een verwachte dataset. Nu gaan we de ondersteuning van DBUnit ontdekken voor het aanpassen van data-assertions.

4.1. Beweren met een SQL-query

Een eenvoudige manier om de werkelijke toestand te controleren, is met een SQL-query.

In dit voorbeeld voegen we een nieuw record in de tabel CLIENTS in en verifiëren we de inhoud van de zojuist gemaakte rij. We hebben de verwachte output gedefinieerd in een apart XML-bestand, en de werkelijke rijwaarde geëxtraheerd door een SQL-query:

@Test openbare leegte gegevenDataSet_whenInsert_thenTableHasNewClient () genereert Uitzondering {probeer (InputStream is = getClass (). GetClassLoader (). GetResourceAsStream ("dbunit / verwachte-gebruiker.xml")) {IDataSet verwachteDataSet) (nieuw FlatXml is build) (nieuw FlatXml is). ITable verwachteTable = verwachteDataSet.getTable ("KLANTEN"); Verbinding conn = getDataSource (). GetConnection (); conn.createStatement () .executeUpdate ("INSERT IN CLIENTS (voornaam, achternaam) VALUES ('John', 'Jansen')"); ITable actualData = getConnection () .createQueryTable ("resultaat_naam", "SELECTEER * VAN KLANTEN WAAR last_name =" Jansen ""); assertEqualsIgnoreCols (verwachteTabel, actualData, nieuwe string [] {"id"}); }}

De getConnection () methode van de DBTestCase ancestor class retourneert een DBUnit-specifieke representatie van de gegevensbronverbinding (an IDatabaseConnection voorbeeld). De createQueryTable () methode van de IDatabaseConnection kan worden gebruikt om actuele gegevens uit de database op te halen, ter vergelijking met de verwachte databasestatus, met behulp van de Assertion.assertEquals () methode. De SQL-query is doorgegeven createQueryTable () is de vraag die we willen testen. Het retourneert een Tafel instantie die we gebruiken om onze bewering te doen.

4.2. Kolommen negeren

Soms willen we bij databasetests enkele kolommen van de werkelijke tabellen negeren. Dit zijn meestal automatisch gegenereerde waarden die we niet strikt kunnen controleren, zoals gegenereerde primaire sleutels of huidige tijdstempels.

We zouden dit kunnen doen door de kolommen weg te laten van de SELECT-clausules in de SQL-query's, maar DBUnit biedt een handiger hulpprogramma om dit te bereiken. Met de statische methoden van de DefaultColumnFilter klasse kunnen we een nieuwe maken ITable instantie van een bestaande door enkele kolommen uit te sluiten, zoals hier getoond:

@Test openbare leegte gegevenDataSet_whenInsert_thenGetResultsAreStillEqualIfIgnoringColumnsWithDifferentProduced () gooit uitzondering {Connection connection = tester.getConnection (). GetConnection (); String [] uitgeslotenColumns = {"id", "geproduceerd"}; probeer (InputStream is = getClass (). getClassLoader () .getResourceAsStream ("dbunit / verwacht-negeren-geregistreerd_at.xml")) {IDataSet verwachteDataSet = nieuwe FlatXmlDataSetBuilder (). build (is); ITable verwachteTable = uitgeslotenColumnsTable (verwachteDataSet.getTable ("ITEMS"), uitgeslotenColumns); connection.createStatement () .executeUpdate ("INVOEGEN IN ITEMS (titel, prijs, geproduceerd) WAARDEN ('Ketting', 199,99, nu ())"); IDataSet databaseDataSet = tester.getConnection (). CreateDataSet (); ITable actualTable = ExclusiefColumnsTable (databaseDataSet.getTable ("ITEMS"), ExclusiefColumns); assertEquals (verwachteTable, actualTable); }}

4.3. Meerdere storingen onderzoeken

Als DBUnit vindt een onjuiste waarde, dan gooit het onmiddellijk een AssertionFout.

In specifieke gevallen kunnen we de DiffCollectingFailureHandler klasse, die we kunnen doorgeven aan de Assertion.assertEquals () methode als derde argument.

Deze storingsafhandelaar verzamelt alle storingen in plaats van te stoppen bij de eerste, dat wil zeggen de Assertion.assertEquals () methode zal altijd slagen als we de DiffCollectingFailureHandler. Daarom zullen we programmatisch moeten controleren of de handler fouten heeft gevonden:

@Test openbare leegte gegevenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​() genereert uitzondering {probeer (InputStream is = getClass (). GetClassLoader () .getResourceAsStream ("dbunit / verwacht-meerdere-verwachte mislukkingen.xml is nieuw. ); ITable verwachteTable = verwachteDataSet.getTable ("ITEMS"); Verbinding conn = getDataSource (). GetConnection (); DiffCollectingFailureHandler collectionHandler = nieuw DiffCollectingFailureHandler (); conn.createStatement () .executeUpdate ("INSERT IN ITEMS (titel, prijs) WAARDEN ('Batterij', '1000000')"); ITable actualData = getConnection (). CreateDataSet (). GetTable ("ITEMS"); assertEquals (verwachteTable, actualData, collectionHandler); if (! CollectingHandler.getDiffList (). isEmpty ()) {String message = (String) CollectingHandler.getDiffList () .stream () .map (d -> formatDifference ((Difference) d)) .collect (samenvoegen ("\ n ")); logger.error (() -> bericht); }}} privé statische String formatDifference (verschil verschil) {retourneer "verwachte waarde in" + diff.getExpectedTable () .getTableMetaData () .getTableName () + "." + diff.getColumnName () + "rij" + diff.getRowIndex () + ":" + diff.getExpectedValue () + ", maar was:" + diff.getActualValue (); }

Verder levert de handler de storingen in de vorm van Verschil instanties, waarmee we de fouten kunnen formatteren.

Na het uitvoeren van de test krijgen we een opgemaakt rapport:

java.lang.AssertionError: verwachte waarde in ITEMS.price rij 5: 199,99, maar was: 1000000.0 verwachte waarde in ITEMS. produceerde rij 5: 2019-03-23, maar was: null verwachte waarde in ITEMS.title rij 5: ketting , maar was: Batterij op com.baeldung.dbunit.DataSourceDBUnitTest.givenDataSet_whenInsertUnexpectedData_thenFailOnAllUnexpectedValues ​​(DataSourceDBUnitTest.java:91)

Het is belangrijk op te merken dat we op dit moment verwachtten dat het nieuwe item een ​​prijs van 199,99 zou hebben, maar dat het 1000000,0 was. Dan zien we dat de productiedatum 2019-03-23 ​​is, maar uiteindelijk was het nul. Ten slotte was het verwachte item een ​​ketting en in plaats daarvan kregen we een batterij.

5. Conclusie

In dit artikel hebben we gezien hoe DBUnit een declaratieve manier om testgegevens te definiëren naar test de gegevenstoegangslagen van Java-toepassingen.

Zoals altijd is de volledige broncode voor de voorbeelden beschikbaar op GitHub.


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