Gambas Unit-Tests

gb.test ist eine Gambas-Komponente für Unittesting und testgetriebene Entwicklung (TDD). Mit dieser Komponente können Sie Tests für Ihr Gambas-Programm erstellen, Sie können Software testgetrieben entwickeln (erst den Test schreiben, dann die Funktionalität programmieren) und Sie können sicherstellen, dass beim Refactoring oder bei der Verbesserung Ihrer Software die gewünschten Ergebnisse Ihres Codes gleich bleiben. Daher ist gb.test hilfreich, um eine bessere Stabilität und höhere Zuverlässigkeit von Gambas-Programmen zu gewährleisten.

Sie können die Tests in spezielle Testklassen (Klassendateien mit der Endung .test) schreiben.

Sobald Sie Tests geschrieben haben, können Sie in der Gambas IDE mit der Taste F4 die Tests laufen lassen.

gb.test führt die Tests aus, und die Ergebnisse werden als TAP-String zusammen mit einer Zusammenfassung ausgegeben. Sie können die Tests in der Gambas-IDE starten und den Fortschritt der Tests sowie das Ergebnis in der IDE auf der Registerkarte Unit Tests verfolgen. Die Zusammenfassung am Ende zeigt "PASSED" oder "FAILED" an, so dass Sie leicht erkennen können, ob Ihre Tests erfolgreich waren oder nicht. Das Ergebnis kann aber auch mit jedem beliebigen Tap Consumer angezeigt, analysiert oder betrachtet werden.

Sie können die Tests Ihres Projekts auch auf der Kommandozeile ausführen. gb.test bietet also die Möglichkeit, Tests automatisch auszuführen.

Wie gb.test funktioniert

gb.test ist dazu da, ein Projekt von innen heraus zu testen. Es kann mit seinen Tests auf alle Prozeduren und Variablen zugreifen, die innerhalb eines Projekts öffentlich sind.

Standardmäßig führt gb.test alle Tests aus, die in einem Projekt vorhanden sind. Die Tests sind in Testmodulen gruppiert. Testmodule sind Klassen mit der Erweiterung .test. Sie enthalten öffentliche Methoden (wir nennen sie Testmethoden). Die Namen der Testmethoden dürfen nicht mit _ beginnen.

gb.test organisiert die Reihenfolge, in der die Testmethoden in Testmodulen aufgerufen werden, in alphabetischer Reihenfolge. Daraus ergibt sich diese Reihenfolge der Ausführung:

TestModuleA.TestMethodA
TestModuleA.TestMethodB
...
TestModuleB.TestMethodA
TestModuleB.TestMethodB

Die Testmethoden selbst enthalten die eigentlichen Tests, die mit Methoden der Klasse 'Assert' durchgeführt werden. Die Klasse 'Assert' stellt verschiedene Assertions zur Verfügung, die im gb.test-Prozess geprüft werden.

Beispielsweise kann mit der Behauptung 'Assert.Equals(Got as String, Expected as String)' getestet werden, ob der Inhalt der Variablen 'Got' mit dem Inhalt der Variablen 'Expected' identisch ist.

Wenn ja, gibt gb.test 'ok' aus, wenn nein, gibt gb.test 'not ok' auf Stdout aus.

Grundsätzlich arbeitet gb.test also alle Assertions in allen Testmethoden in allen Testmodulen eines Projekts ab, prüft die Assertions und gibt das Ergebnis auf stdout aus. Zusätzlich führt gb.test auch eine Statistik durch und gibt am Ende eine Zusammenfassung aus, die zeigt, ob und welche Fehler gefunden wurden.

Wenn Sie nicht möchten, dass gb.test alle Tests ausführt, die es in einem Projekt findet, können Sie seine Arbeit mit so genannten Testsuiten auf einzelne oder Gruppen von Tests beschränken. Eine Testsuite ist im Grunde nichts anderes als eine Zeichenkette, die die Namen der gewünschten Tests enthält, die gb.test ausführen soll.

Beispiel

Ein Beispiel findet sich in diesem einfachen Gambas-Projekt:

Test-Modul

In der testgetriebenen Entwicklung ist es üblich, zuerst den Test zu schreiben, den das zukünftige Programm später erfüllen soll. Daher beginnen wir mit der Erstellung eines Testmoduls.

Dies ist eine Klasse, die wie jede andere Gambas-Klasse mit der Endung ".test" benannt wird, zum Beispiel "THelloWorld.test". Diese Klasse enthält einen oder mehrere Tests, das sind öffentliche Subs, deren Name keinen Unterstrich enthalten darf:

' Gambas test module file
''' Test module THelloWorld

Public Sub AHelloWorld()

  Test.Note("I am the first test, because my name starts with A.")
  Assert.Equals(Hello.World(), "Hello World", "HW strings should be equal")

End

Mit den von der Klasse Assert bereitgestellten Methoden können Sie die Ausgabe eines beliebigen öffentlichen Zustands (Variable, Konstante oder Funktion) in Ihrem Projekt testen.

Modul (Funktion), das getestet wird:

Nun, da wir den Test geschrieben haben, ist es an der Zeit, das Programm zu entwickeln, das den Test ausführen soll. Wir erstellen also eine Funktion "World" in einem Modul "Hello" in unserem Projekt:

' Gambas module file

''' Module is named "Hello"

'' Returns "World"
Public Function World() As String
   
  Return "Hello World"
    
End

Ausführen des Tests

Wenn Sie mit der Gambas-IDE arbeiten, können Sie F4 drücken, um Ihre Tests laufen zu lassen. Die IDE zeigt Ihnen die Registerkarte "Unit tests" mit diesem Inhalt:

1..1

Test THello:AHelloWorld
  # I am the first test, because my name starts with A.
  ok 1 - HW strings should be equal
  1..1
ok 1 - THello:AHelloWorld

# Ran: 'THello.AHelloWorld'
#
# PASSED

Wenn ein Fehler auftritt, wird FAILED anstelle von PASSED gemeldet und der Ort des Fehlers wird angezeigt. Wenn Sie den Code debuggen möchten, können Sie an einer beliebigen Stelle in Ihrem Test- oder Produktionscode einen Haltepunkt setzen, erneut <F4> drücken und das Debugging starten.

Testmodule und Testmethoden können wie alle Gambas-Module oder -Methoden benannt werden, mit der Ausnahme, dass eine Testmethode nicht _Setup(), _Teardown(), _SetupEach() oder _TeardownEach() heißen darf und ihr Name keinen Unterstrich enthalten darf.

Testsuites

Wenn Sie Shift-F4 drücken, können Sie in der Gambas-IDE so genannte "Testsuiten" erstellen. Dies ist praktisch, wenn Sie viele Tests haben, aber nur einen oder ein paar davon zufällig ausführen müssen. Sie können eine Vielzahl von Testsuiten erstellen und diese verwenden, um verschiedene Aspekte Ihres Projekts separat zu testen.

Die Testsuiten werden in der Datei .test im Projektpfad gespeichert.

Testen Sie Ihr Projekt auf der Konsole

Sie können Ihr Projekt auch auf der Konsole testen. Dazu muss es zunächst kompiliert werden. Der Befehl gbx3 -T "" /pfad/zu/mein/projekt führt die Unittests aus und gibt das Ergebnis auf der Standardausgabe aus. Auf die gleiche Weise können Sie einzelne Tests oder eine Anordnung von Tests aufrufen, die in der Datei .test gespeichert sind, nachdem Sie eine Testsuite erstellt haben.

Sie können eine Testsuite sogar über ihren Namen ausführen lassen, indem Sie ein vorangestelltes "@" an ihren Namen anhängen, wenn Sie sie mit gbx3 ausführen lassen:

gbx3 -T "@my first testsuite" /path/to/my/project

Wenn Ihr Projekt auf das Vorhandensein von Umgebungsvariablen angewiesen ist, können Sie diese in der Befehlszeile definieren:

MyEnvVar=1 gbx3 -T "@my first testsuite" /path/to/my/project

Umgebungsvariablen, die im Dialogfeld Projekteigenschaften der Gambas-IDE definiert sind, werden nicht berücksichtigt.

Testfixture

Manchmal ist es notwendig, eine "Fixture" zu erstellen, eine spezielle Umgebung für einen Test oder mehrere Tests, und diese Umgebung nach Abschluss des Tests wieder zu löschen. Zum Beispiel sollte zu Beginn aller Tests eine Datenbankverbindung hergestellt werden, für jede einzelne Testmethode sollten einige Tabellen für den Test erstellt und gelöscht werden und die Datenbankverbindung sollte am Ende geschlossen werden. Dies kann mit den Funktionen _Setup... und _Teardown... innerhalb des Testmoduls erledigt werden.

Sub _Setup() und Sub _Teardown()

Sie können Methoden mit diesen Namen erstellen, um eine Umgebung für alle Testmethoden innerhalb eines Testbausteins zu schaffen. Zu Beginn wird _Setup() aufgerufen und nachdem alle Testmethoden innerhalb des Testbausteins fertig sind, können Sie die Umgebung mit _Teardown() zerstören.

Sub _SetupEach() und Sub _TeardownEach()

Sie können Methoden mit diesen Namen erstellen, um eine Umgebung für jede Testmethode zu erstellen, bevor sie aufgerufen wird, und um sie anschließend zu zerstören. Wenn Sie fünf Testmethoden in Ihrem Testmodul haben, werden diese Funktionen fünfmal aufgerufen, _SetupEach() vor jeder Testmethode, _TeardownEach() nach jeder Testmethode.

Tests planen

Es wäre ziemlich blöd, wenn Ihr Testsystem aus unbekannten Gründen einzelne Tests verschluckt und Ihnen nie anzeigt, dass sie nicht gelaufen sind. Um sich davor zu schützen, gibt es eine Möglichkeit, einen Plan festzulegen, der die Anzahl der Assertions definiert, die innerhalb einer Testmethode ausgeführt werden müssen. Und das geht so:

' Gambas test file
''' Test module THelloWorld

Public Sub AHelloWorld()

  '' Defines the count of assertions in this test method
  Test.Plan(1)

  Assert.Equals(Hello.World(), "Hello World", "HW strings should be equal")

End

Wenn die Tests den Plan nicht erfüllt haben, zeigt das System "FAILED" an und nennt Ihnen den Grund.