Ich akzeptierte die Bequemlichkeit, Unit-Tests für mein Lieblings-C ++ zu verwenden, und versuchte, meine Erfahrungen auf TSQL zu übertragen, zumal der neue Arbeitgeber eine nützliche Initiative vor Ort liebt und Brötchen dafür verteilt.
Ich habe einige
bekannte Frameworks durchgesehen
und bin zu dem Schluss gekommen, dass sie in der Regel sperrig sind und zusätzliche Syntax mit sich bringen, die zusätzlich untersucht werden muss.
Einige Frameworks funktionieren wunderbar und erfreuen das Auge des Managers, dem sie angezeigt werden, haben jedoch eine Reihe von Einschränkungen, die mir nicht gefallen haben.
Ich wollte alles auf rein koscher-halal-orthodoxer TSQL implementieren.
Von Zeit zu Zeit habe ich mich entschlossen, es mit Ihnen zu teilen, da ich einige Jahre lang von der Hauptentwicklung abgelenkt war, um die Struktur des Skripts zu verbessern (aber es gelang mir trotzdem, 3,5 MB Skripte zu produzieren).
Meine grundlegenden Anforderungen waren einfach: Ich muss jeden Komponententest in einer Datei durchführen, ohne dass Gesten und spezielle Softwaretools erforderlich sind - nur Hardcore: sqlcmd oder MSSMS.
An der Datenbank, in der der Test durchgeführt wird, werden keine Änderungen vorgenommen. Alles wird auf den Anfang des Skripts zurückgesetzt.
Nur eine hat eine Einschränkung festgelegt - der Test sollte in einer leeren Datenbank funktionieren (möglicherweise sind es anfängliche Daten), da Sie sonst müde werden, alle Optionen zu zerlegen.
Die Hauptaufgabe besteht darin, die Logik zu testen und die Integrität der Logik aufrechtzuerhalten.
Dazu habe ich zu Beginn des Tests folgende Überschrift gesetzt:
SET QUOTED_IDENTIFIER ON GO PRINT '-------------------------------- CLR Unit tests for Habr Logic ---------------------------------' IF 0 < ( SELECT count(*) FROM device) begin RAISERROR ('FAILED: database must be empty for this unit test', 16, -1 ) end GO
Ich versuche, Unit-Tests nicht länger als ein paar Bildschirme zu erstellen, obwohl dies bei komplexer Logik nicht einfach ist.
Ein typischer Unit-Test sieht so aus und besteht aus 3 Hauptteilen:
BEGIN TRAN TestClr2 declare @test_name sysname = (select TOP 1 name from sys.dm_tran_active_transactions WHERE transaction_type = 1 ORDER BY transaction_begin_time DESC) + ' [fn_calculate_dev_status] record for device has wrong range' BEGIN TRY SET NOCOUNT ON;
- 1. Daten für den Unit-Test vorbereitenHier können wir die erforderlichen Tabellen mit Daten füllen und einige temporäre Variablen oder Tabellen vorbereiten, um den Code im Testabschnitt nicht zu überladen.
- 2. Unit-Test durchführenHier geht es in der Regel entweder um einen Funktionsaufruf oder eine Prozedur oder um eine Tabellenänderung, wenn wir die Triggerlogik testen.
- 3. ErgebnisüberprüfungIn diesem Teil des Tests überprüfen wir, wie sich der Status von Datenbankobjekten oder das Ergebnis der getesteten Funktionsprozedur geändert hat.
Wenn die Prozedurfunktion einen Datensatz zurückgibt, fügen wir ihn in die temporäre Tabelle ein und analysieren ihn bereits.
Aggregierte und vorbereitete Ergebnisse werden mit dem Standard verglichen und lösen eine Ausnahme aus, wenn alles andere fehlschlägt.
Mit Oracle ist alles etwas komplizierter - ich konnte den Test nicht in dieser Form und in derselben Ideologie schreiben und ausführen, sondern aus ein wenig Erfahrung - wir haben die Unterstützung von Oracle für unser Produkt eingestellt.
Jeder Komponententest wird als Verfahren ausgegeben:
CREATE OR REPLACE PROCEDURE UnitTest9_TRG_JOBLOGDETAIL AS v_message VARCHAR2(255) := 'UnitTest9_TRG_JOBLOGDETAIL: INSERT joblogdetail]- joblogdetail_result not Failed and joblogdetail_endtime is null '; v_maxdate date := '2014/01/01'; v_cnt NUMBER := 0; BEGIN savepoint my_savepoint; <b>
In derselben Testdatei am Ende müssen Sie eine Datenbankbereinigung der erstellten und ausgeführten Tests durchführen.
commit; / set serveroutput on; SET FEEDBACK OFF; spool C:\dist\test.spl; exec UnitTest_empty_database; exec UnitTest3297_TRGBFR_UDEVICE(1); exec UnitTest5_TRG_BF_UDEVICE; exec UnitTest_3062a; ... spool off; / DROP PROCEDURE UnitTest_3062; DROP PROCEDURE UnitTest_BIRDIESEC_3344; DROP PROCEDURE UnitTest_empty_database; ... SET FEEDBACK ON; commit;
Das ist alles
Dann erstellen Sie einfach Dateien, die in Kategorien des Typs unterteilt sind: Trigger, Funktionen, Prozeduren, Berichte, große und spezielle Objekte der Geschäftslogik und natürlich für jedes Datenbankobjekt.
Fast alle Datenbankentwickler runzeln die Stirn und sagen: Warum sollte ich Tester dies tun lassen? Wenn die Datenbank überhaupt keine Logik aus dem Wort hat, stimme ich ihnen zu, aber wenn es viel davon gibt, sparen sie natürlich die Nerven, den Ruf und das Geld.
Ein Beispiel.
Wir haben in der Weboberfläche Bäume logischer Verbindungen zwischen Baumobjekten wie Amerika -> Kanada -> Ontario -> Waterloo, Asien -> Japan -> Tokio -> Ebina, dh eine ganze Reihe von geografischen Büros.
Jeder dieser Knoten hat sehr komplexe Regeln, der Benutzer oder die Regel oder der Generator weist Geräte zu.
Infolgedessen zerstören selbst die in Schritten ausführlich beschriebenen Anweisungen alle, selbst diejenigen, die an der Diskussion und Entwicklung dieser Logik teilgenommen haben.
Mehr als fünfzig Schritte der Anweisung mit unterschiedlichen Datensätzen - alles ist detailliert dokumentiert.
Jede Änderung oder Ergänzung der Logik ist eine Uhr der manuellen Überprüfung, dass nichts kaputt gegangen ist.
Death Refactoring ist ähnlich.
Nachdem ich die Logik mit Unit-Tests behandelt habe, wird alles mit Seide überprüft und ich bin sicher, dass alles so funktioniert, wie es sollte.
Jeder Java-Entwickler, der auf mich zurückgreift, Donner und Blitz wirft (sich Gedanken über meine krummen Hände macht), kann einfach durch Ausführen des entsprechenden Tests eingerichtet werden.
Ein paar Minuten und alle sind zufrieden. Jede schwerwiegende Codeänderung in meiner Abwesenheit wird mir schnell per E-Mail gemeldet.
Als fauler Mensch habe ich mich natürlich entschlossen, alles für Continuous Automation zu automatisieren, und Brei aus Batches und Python geschrieben.
Ich bitte Sie, in der täglichen Entwicklung von fast einem Dutzend Sprachen und Umgebungen, zwischen denen Sie springen müssen, etwas zu tun. Es gibt einen katastrophalen Zeitmangel, um alles zu lecken und es professionell aussehen zu lassen.
Ich wollte nicht alles mit Windows Powershell machen - unsere Sprünge laufen immer noch hier und da auf eingebetteten Windows95.
Ich wollte alle Aufrufe in Python ausführen, aber es stellte sich heraus, dass einige SQL-Konstrukte (XML-Parsing in cte) nicht nur in der Python-Bibliothek, sondern auch in .NET unterstützt werden. Deshalb habe ich die Skripterstellung über sqlcmd durchgeführt.
Der Code wird
hier veröffentlicht .
Um ein funktionierendes Beispiel auszuführen, bearbeiten Sie einfach zwei Dateien: smtppart.py und config.ini - SMTP-Servername, Port und E-Mail, in denen Fehlermeldungen abgelegt werden.
Die Skripte versuchen zunächst, die neuesten Updates von svn zu erhalten (durch Ihre eigenen ersetzen - git, perforce, ...).
Anschließend wird aus Skripten mit einem zufälligen Namen eine saubere Basis erstellt, darin werden Komponententests gestartet und die Basis gelöscht.
Das Erstellen einer Datenbank mit 80-MB-Skripten und 3,5-MB-Tests (der Hauptteil des Schemas wurde bereits vor meinem Eintritt in das Unternehmen durchgeführt, sodass ich nur meinen Teil getestet habe) erfolgt auf meinem Computer in ca. 15 Minuten. Ich habe gerade Zeit, vor dem endgültigen Commit eine Tasse Kaffee zu trinken.
Wenn Fehler aufgetreten sind, werden die Ergebnisse des Fehlers per E-Mail gesendet.
Die Installation der Abhängigkeit wird in der Datei readme.txt beschrieben
Nach jeder Codeänderung müssen Sie den Code-Hash (der in der Befehlszeile angezeigt wird) in der Datei config.ini manuell festlegen. Die Meldung wird auch dann angezeigt, wenn der Code geändert wird und nichts beschädigt ist. So kann ich die Änderungen im Code steuern, ohne die Änderungen überprüfen zu können meine vorherige Beteiligung.

Der Start aller Komponententests in der Datei autorun.bat kann im
Windows Task Scheduler abgelegt werden und 1-2 Tage am Tag vor dem Erstellen des Unternehmens oder nach dem Verlassen des Hauses ausgeführt werden. Wenn abends etwas kaputt geht, können Sie sich ansehen, was vor dem Fernseher passiert ist, und es schnell beheben.
Ich weiß, dass es bei Komponententests am schwierigsten ist, alles einzurichten, und dann ist es einfach und angenehm, Tests zu schreiben, obwohl es schwierig und schwierig, aber notwendig sein kann. Viel Glück beim Testen, ich hoffe mein Rat wird jemandem helfen.
Ich werde gerne Ratschläge annehmen, wenn irgendwo etwas verbessert werden kann, und den Code kämmen, nicht streng beurteilen.