Unit testing (MySQL)

Uit De Vliegende Brigade
Ga naar: navigatie, zoeken
M'n eerste vier tests! Dit betreft één 'procedure' maar wel voor vier verschillende talen en met deels verschillende sprocs die worden aangeroepen. Ze werken met een testbestand van 100 regels. Executie duurt ca. een halve minuut per script

In de herfst van 2018 ben ik unit testing gaan toepassen voor mijn datawarehousing-activiteiten in MySQL.

Waarom?

Scripts actueel houden

Ik werk veel met scripts die voornamelijk uit calls naar sprocs bestaan. Die sprocs veranderen echter voortdurend, maar die scripts gebruik ik meestal slechts om de paar maanden. Als ik na een paar maanden, weer zo'n script nodig heb, is het vaak een gedoe om de juiste versie van dat script terug te vinden en om het weer aan de praat te krijgen. Omdat het meestal alweer een paar maanden geleden was dat ik voor het laatste met dat script werkte, brengt dit vaak flinke 'opstartkosten' met zich mee.

Dit probleem is nog erger voor klanten waar ik niet zo vaak datawarehousing voor doe: In de tussentijd zijn er alweer zo veel nieuwe inzichten en sprocs, dat het me de grootste moeite kost om die oude scripts weer aan de praat te krijgen.

Debugging

Ooit heb ik begrepen, dat unit testing primair is bedoeld om te borgen dat alles blijft werken. Oftewel: Als jij een bepaalde routine schrijft waardoor bij unit testing blijkt dat twee andere tests het niet mee doen, dan is het jouw verantwoordelijkheid om dat te fixen.

Die situatie geldt hier ook: Als ik tijdens refactoring een bepaalde routine aanpas, dan kan het zomaar gebeuren dat een aantal scripts niet meer functioneren. Unit testing helpt om dat te ondervangen.

Kruft vermijden

Op dit moment (20 dec. 2018) heeft het DWH van een klant van mij, 110 sprocs. Van de meeste van die sprocs weet ik waar ze voor dienen. Maar niet voor allemaal.

Idealiter helpt unit testing om bij te houden wat courante sprocs zijn, en wat weg mag. En met een beetje mazzel, help dit ook om tabellen te identificeren die niet meer gebruikt worden.

Hoe?

Elke test is een complete procedure

Het woord unit in unit testing impliceert dat je de losse 'bouwstenen' van een applicatie test. Ik geloof dat dat niet is wat ik doe: Ik test complete procedures, want dat is waar het me om gaat. Effectief worden die bouwstenen daarmee ook getest. Misschien dat deze aanpak beter bij mijn situatie past, omdat ik maar een handjevol van deze procedures heb - Een stuk of 20 op dit moment (19 sep. 2018)

Elke test is een SQL-script

  • Idealiter zou een test een sproc zijn, zodat ze in de database zelf zijn opgeslagen. Die aanpak blijkt niet handig te zijn, want sprocs genereren vrijwel geen debug-informatie
  • Alle tests in één script proppen, is ook niet handig: Dat wordt al snel honderden regels, en als ergens halverwege een test niet werkt, moet je al snel dat script aanpassen om te debuggen - Dat werkt niet
  • Daarom: Elke test is een SQL-script.

Testen gaat (voorlopig) via MySQL Workbench

  • Als ik scripts uitvoer via de MySQL client, krijg ik geen debug-informatie - Da's niet handig. Ongetwijfeld valt dat te ondervangen via logboeken, maar da's extra werk, wat op dit moment onnodig is
  • Scripts in sproc-formaar genereren eveneens vrijwel geen debug-info (zie hoofdstuk hiervoor)
  • Executie via MySQL Workbench, genereert wél debug-informatie → Keuze is duidelijk.

Elk script moet je (helaas) apart executeren

Zo ver ik kan nagaan, kan een script in MySQL Workbench, niet een ander script aanroepen (het commando source is een MySQL client-commando en werkt niet binnen MySQL Workbench) → Elk script apart openen en execturen - Daar valt voorlopig prima mee te leven.

Scripts zijn klant- & projectonafhankelijk

  • Alle scripts staan in een losse map DWH - Unit tests
  • Elk script begint met het commando use met de naam van de betreffende database
  • Op deze manier kan ik met één test-procedure voor alle klanten en alle projecten testen.

Wat wordt er getest?

  • Altijd een lastig onderwerp rondom geautomatiseerd testen: Hoe ver ga je precies met testen? Test je alleen of routines zonder runtime-errors executeren? Test je GUI's (lastig!) of waar daar tussenin? Mogelijk dat dit onderwerp strict gezien, buiten unit testing valt, omdat je (geloof ik) binnen unit testing vooral routines test. Dus of bepaalde input en output met elkaar overeenkomen
  • In mijn geval is de uiteindelijk output van scripts een export-bestand in de /tmp-map. Da's lastig automatisch te testen.

Runtime-errors

Dit is een inkoppertje: Als er een runtime-error optreedt, moet er iets gefixet worden.

Exportbestanden naar schijf geschreven?

Vrij elementair & essentiëel: Belanden er export-bestanden in de /tmp-map? Dit is niet iets dat ik op dit moment geautomatiseerd verifiëer. Ik moet dus zelf die map openen en het aantal bestanden tellen - Geen probleem.

Exportbestanden inspecteren?

Dit wordt gelijk een stuk vervelenden: Moet ik al die exportbestanden openen en inspecteren? Dat ga ik nooit doen. En ik denk dat dat ok is: Als scripts executeren en er worden bestanden naar schijf geschreven, dan ben ik al een flink geholpen.

Procedure

  • Met drag-en-drop kun je in één keer alle scripts openen in MySQL Workbench - Dat scheelt veel tijd!
  • Executeer het eerste script
  • Script succesvol doorlopen? → Sluit het betreffende tabblad
  • Herhaal totdat alle scripts succesvol zijn doorlopen.

Zie ook