Follow Us on Twitter

Unittesten in SQL Developer

Gepubliceerd in

Februari 2010 - Unittesten is voor een Oracle database-ontwikkelaar geen dagelijkse bezigheid. In Java is unittesten een bekend begrip, maar een Oracle PL/SQL ontwikkelaar komt zelden in aanraking met unittesten. Dat is jammer, want unittesten komt de kwaliteit van de opgeleverde software ten goede, vooral in een omgeving waar regelmatig codewijzigingen plaatsvinden. Een belangrijke reden is dat er bijna geen (gratis) unittestsoftware voor PL/SQL code bestaat. Er bestaat een open source framework genaamd utPLSQL, maar dit is een framework zonder user interface en enkel een hulpmiddel om handmatig testcode te schrijven. Bovendien wordt aan utPLSQL al een tijd niet ontwikkeld. Quest biedt wel een tool met een user interface om unittesten volledig te automatiseren, maar deze Quest Code Tester is echter niet gratis. Oracle komt nu zelf met een oplossing: versie 2.1 van Oracle SQL Developer heeft namelijk unittestfunctionaliteit. We bespreken in dit Whitebook hoe unittesten in SQL Developer in z'n werk gaat en of dit betekent dat unittesten voor PL/SQL ontwikkelaars toegankelijker wordt.

Opzetten van de repository

Voor het unittesten in SQL Developer is een repository vereist. De unittest repository is een set van database-objecten waar SQL Developer de gegevens ten behoeve van het unittesten bewaart. Een repository aanmaken kan via het menu Tools->Unit Test, kies hier voor de optie Select Current Repository.

Select current repository 
  Figuur 1, Select current repository

De volgende stap is het selecteren van het databaseschema waar de repository wordt aangemaakt. Dit kan hetzelfde schema zijn als het schema waarvoor getest gaat worden, maar het is verstandig dit in een ander schema te installeren om zo de unittest objecten apart te houden. In dit geval creëren we een nieuw schema unit_test.

Rechten uitdelen voor het gebruik van de unittesting repository kan via het menu Tools->Unit Test->Manage Users.

Het Manage Users scherm
  Figuur 2, Het Manage Users scherm

In dit scherm kan een databasegebruiker user of administrator van de repository worden gemaakt. Op de database betekent dit dat een databasegebruiker de rol UT_REPOS_USER of UT_REPOS_ADMINISTRATOR krijgt. Daarnaast is het nodig de repository shared te maken: Tools->Unit Test->Select As Shared Repository. Deze stap is nodig zodat andere gebruikers ook deze repository kunnen benaderen, een unshared repository kan alleen benaderd worden via de databasegebruiker die de repository heeft aangemaakt.

Hierna kan de gebruiker (in dit geval HR) beginnen met unittesten door de repository te selecteren via het menu Tools->Unit Test->Select Current Repository, SQL Developer zal dan de shared repository gebruiken. 

Definiëren van een unittest

Een unittest wordt gedefinieerd voor een procedure of een functie, al dan niet in een package. Het aanmaken van een unittest kan eenvoudig door rechts te klikken op een functie of procedure en voor de optie Create unit test te kiezen. Een tweede optie is via de unittest tab (via het menu: View->Unit Test).

Tab unittest
  Figuur 3, Tab unittest

Door in deze tab rechts te klikken op het item Tests kan door middel van de optie Create Test ook een unittest worden aangemaakt.

De volgende stap is het opgeven van de naam en het soort unittest. In dit voorbeeld maken we een unittest voor de procedure add_job_history.

naam en soort test
  Figuur 4, naam en soort test

Er zijn twee soorten unittests:

 

  • Create with single Dummy implementation: via deze optie wordt een standaard unittest gemaakt.
  • Seed/Create implementations using lookup values: via deze optie kunnen de input parameters via een lijst van waarden worden gegenereerd. In het hoofdstuk Overige functionaliteiten wordt dit uitgelegd.

 

In dit voorbeeld maken we een standaard unittest. De volgende stap is het selecteren van een Startup actie.

startup actie
  Figuur 5, startup actie

Met een startup actie kan code worden uitgevoerd vóór het starten van de unittest. Een Table or row copy maakt het mogelijk via een wizard een kopie van een rij of hele tabel te maken. Via User PL/Sql Code kan zelf PL/SQL code worden geschreven als startup actie.

startup process scherm
  Figuur 6, startup process scherm

Via de optie Publish to Library kan deze startup code worden toegevoegd aan de unittest Library. De definities die in deze Library worden toegevoegd, kunnen worden hergebruikt in andere unittests. Voor dit voorbeeld definiëren we geen startup actie.

De volgende stap is het opgeven van de input parameters voor de test. Voor elke parameter kan handmatig een waarde worden gedefineerd of de parameters kunnen worden opgehaald door middel van een query (Dynamic Value Query). Indien deze query meerdere rijen retourneert, dan zal voor elke rij de unittest worden uitgevoerd.

In het voorbeeld voeren we handmatig geldige waarden in voor de parameters en is het verwachte resultaat dat de test succesvol wordt uitgevoerd (Expected Result = Success). Een mogelijk andere test is het opgeven een ongeldige parameter met als verwacht resultaat een exception.

input parameters
  Figuur 7, input parameters

De volgende stap is het definiëren van één of meer validaties na het uitvoeren van de procedure. In de vorige stap is gedefinieerd dat de functie succesvol wordt uitgevoerd en via een validatie kan een verwacht resultaat worden getest. Een validatie wordt gedaan via een query, een boolean functie of PL/SQL code. In dit voorbeeld voeren we een query uit op de tabel job_history om zo te valideren dat de procedure succesvol het record heeft aangemaakt in de tabel.

validaties
  Figuur 8, validaties

In de laatste stap wordt de zogenaamde teardown gedefinieerd. Dit is niks anders dan de code die aan het eind van de test wordt uitgevoerd. Hier kan gekozen worden voor het verwijderen van een tabel, het herstellen van data of zelfgeschreven PL/SQL code.

teardown actie
  Figuur 9, teardown actie

In dit voorbeeld voeren we een rollback uit, zodat het aanmaken van data door de procedure ongedaan wordt gemaakt en de test dus vaker succesvol uitgevoerd kan worden.

Na een samenvatting van de unittest kan het aanmaken van de test worden bevestigd.

Uitvoeren van een unittest

In onderstaand plaatje is de aangemaakte unittest te zien.

Unittest overzicht
  Figuur 10, Unittest overzicht

Aan de linkerkant staat de unittest ADD_JOB_HISTORY. Wat meteen opvalt is dat onder de test ook Test Implementation 1 is aangemaakt. Een unittest heeft altijd minstens een implementatie en indien nodig kunnen er meerdere implementaties worden toegevoegd. Implementaties delen de startup en teardown actie, wat verschilt per implementatie zijn de input-parameters en de validaties.

We voeren de unittest uit en SQL Developer toont vervolgens het resultaat.

Unittest resultaat
  Figuur 11, Unittest resultaat

Van elk onderdeel wordt aangegeven of deze succesvol is afgerond en ook de tijdsduur wordt getoond. In het voorbeeld zijn alle onderdelen succesvol afgerond en daarmee is de unittest geslaagd. Indien in één van de stappen een fout optreedt, zal dit met bijbehorende foutmelding getoond worden.

Naast het handmatig starten van een unittest in SQL Developer, kan een unittest ook worden gestart via de commandline. Bij de SQL Developer installatie is een batch bestand UtUtil aanwezig voor zowel Windows als Linux. Het commando om de unittest ADD_JOB_HISTORY op te starten ziet er zo uit:

UtUtil -run -test -name "ADD_JOB_HISTORY" -repo hr@xe -db hr@xe

Wat meegegeven wordt aan het commando zijn de testnaam, de repository en de naam vande databaseconnectie. Het is goed dat er een commandline optie is om zo de unittest te kunnen schedulen, helaas is deze commandline-interface afhankelijk van de SQL Developer installatie. De connectienaam in het commando is letterlijk de connectienaam in SQL Developer. Er zal dus een SQL Developer installatie gedaan moeten worden op de machine waar de geplande unittest uitgevoerd moet worden.

 

Overige functionaliteiten

Een unittest aanmaken en uitvoeren is de belangrijkste functionaliteit, maar SQL Developer biedt meer functionaliteiten om werken met unittests te vereenvoudigen.

Om verschillende testen te groeperen kan een testsuite worden gebruikt. Zo kan een reeks afzonderlijke unittests in één run worden uitgevoerd. Ook is het mogelijk een startup en teardown actie uit te voeren voor de testsuite.

Een lookup is een lijst van een willekeurig aantal waarden van hetzelfde datatype. Deze lookups kunnen worden gebruikt voor het definiëren van parameters voor de unittest. Een lookup is altijd onderdeel van een categorie, per categorie kan slechts één lookup per datatype voorkomen.

Lookups
  Figuur 12, Lookups

Een lookup wordt zichtbaar bij het definiëren van de parameters van de unittest.

Lookup gebruiken
  Figuur 13, Lookup gebruiken

Na het kiezen van de lookup categorie kan in het input veld de lijst met waarden worden gebruikt. Deze lijst is dus afhankelijk van het datatype, in dit geval wordt hier de lijst van het datatype NUMBER getoond voor de categorie EMP.

Een andere toepassing van de lookups is het genereren van unittest implementaties. Indien bij het aanmaken van een unittest wordt gekozen voor Seed/Create implementations using lookup values zal SQL Developer unittest implementaties genereren. Op basis van een lookup categorie wordt voor alle combinaties van parameter waarden een unittest implementatie aangemaakt. De lookup categorie die hiervoor wordt gebruikt, is in te stellen in de opties van SQL Developer. Een voorbeeld: de functie test_seed heeft twee input parameters van het type NUMBER, de standaard lookup categorie is EMP. Voor het datatype NUMBER zijn twee waarden gedefinieerd: 102 en 110. Indien nu een unittest van het type Seed/Create implementations wordt gekozen, zal SQL Developer vier implementaties genereren, een implementatie voor alle combinaties van 102 en 110 als input parameter (dus de combinaties 102/110, 102/102, 110/102 en 110/110).

Gegenereerde implementaties
  Figuur 14, Gegenereerde implementaties

Conclusie

Unittesten helpt een ontwikkelaar om z'n code met minder fouten op te leveren. In een vroeg stadium van de ontwikkeling met unittesten starten, zet een ontwikkelaar aan om na te denken over waar de functie of procedure aan moet voldoen. Met behulp van een unittest kan de functionaliteit op een verwachte uitkomst worden gecontroleerd, alsmede of foutsituaties juist worden afgehandeld. Na codewijzigingen geven unittests de zekerheid dat de oude functionaliteit nog steeds werkt.

De vraag is of unittesten toegankelijker is gemaakt door de toevoeging van unittestfunctionaliteit in SQL Developer. Het antwoord is duidelijk ja.

De eerste release van de unittestfunctionaliteit heeft zeker nog wel verbeterpunten, maar is al zeer compleet te noemen en werkt naar behoren. Het aanmaken van een unittest is eenvoudig en biedt diverse mogelijkheden om het testen te faciliteren. Via de startup en teardown acties kan de test worden voorbereid en afgesloten en via validaties kan de uitkomst worden gecontroleerd. De library maakt hergebruik van unittest componenten mogelijk. Unittesten kunnen worden gegroepeerd door middel van testsuites. Na het uitvoeren van een test is er een duidelijk overzicht van de resultaten van de diverse stappen. De testresultaten worden in tabellen opgeslagen, hierdoor kunnen eenvoudig rapportages van de unittest resultaten worden gemaakt.

Uiteraard is het meeste werk van unittesten het bedenken van de testen, maar software om deze testen te ondersteunen is zeker een belangrijke factor om hiermee aan de gang te gaan. SQL Developer is toegankelijke software voor een Oracle ontwikkelaar en daarmee is de drempel om met unittesten te starten voor een belangrijk gedeelte weggenomen.

Referenties

Waardering:
 

Reacties

Nieuwe reactie inzenden

De inhoud van dit veld is privé en zal niet openbaar worden gemaakt.

Meer informatie over formaatmogelijkheden

CAPTCHA
Deze vraag is om te testen of u een persoon bent en om spam te voorkomen
Image CAPTCHA
Enter the characters shown in the image.