2 Testdaten und Testcode erzeugen
Um das Projekt "rund" zu machen, etwas, das mich wirklich begeistert: Das Erzeugen von Testdaten und Testcode aus dem Modell!
Dafür verwenden wir den XML-Parser, der in Kapitel 3 beschrieben wurde.
Auch im Bereich des Testens spart dieses Vorgehen viel Handarbeit. Und es sorgt dafür, dass bei Änderungen am Modell die Testdaten und der Testcode automatisch angepasst werden!
Der Gesamtablauf
Der Ablauf der Generierung wird geändert:
-
- Im Schritt 1 werden aus dem Parser-Modell die Testfälle erzeugt und im Testfall-Modell gespeichert.
- In Schritt 2 werden aus dem Testfall-Modell die Testdaten und der Testcode erzeugt.
- Im Schritt 3 wird der Parser-Code generiert.
- Im Schritt 4 wird der Code in das Parser-Projekt kopiert.
Schritt 1: Aus dem Parsermodell die Testfälle erzeugen
Die folgende Grafik zeigt den Ablauf der Testfall-Erzeugung:
Die Hauptarbeit geschieht in Schritt 1, der Model-to-Model-Transformation. Dort erzeuge ich für jeden Testfall eine gültige Baumstruktur.
In den Schritten 2a und 2b wandle ich jede Baumstruktur in eine XML-Datei bzw. in Testcode um. Dafür reichen einfache Model-to-Text-Transformationen.
Schritt 1: Mit Model-to-Model das Modell der Testfälle erzeugen
Mein Ziel ist es, anhand des Modells eine Auswahl an Bäumen zu erzeugen. Dafür erzeuge ich für ein Element in den verschiedenen Testfällen unterschiedliche Anzahlen an Kindern.
Ich orientiere mich dabei lose an einer "Schleifenüberdeckung", d.h. ich prüfe "an den Rändern". Da der Parser dynamische Listen verwendet, kann ich nicht an der "Obergrenze" testen. Daher beschränke ich mich auf die "Untergrenze".
Die 2 in der Spalte "Maximale Anzahl Kinder" ist hier nicht als echtes Maximum zu verstehen, sondern als Repräsentation von "mehr als ein Kind-Element" für die Testfälle.
Multiplizität des Kinds
|
Minimale Anzahl Kinder
|
Maximale Anzahl Kinder
|
ZeroOrOne
|
0 |
1 |
One
|
1 |
1 |
ZeroOrMany
|
0 |
2 |
OneOrMany
|
1 |
2 |
Offen gestanden hatte ich keine Idee, wie viele Testfälle durch diesen Ansatz erzeugt werden würden.
Glauben Sie, die ungefähre Antwort zu kennen? Die Lösung finden Sie am Ende des Artikels.
Verwendete Symbole
Um die Testfälle zu erzeugen, verwende ich Rekursion, Permutationen und Listen von Permutationen. Um es ein wenig anschaulicher erklären zu können, verwende ich die folgenden Symbole.
Das Erzeugen der Testfälle im Detail
Für jedes Element E erzeuge ich alle Permutationen P1, …, Pn seiner Kinder. Und für jedes Kind erzeuge ich wieder alle Permutationen seiner Kinder, und so weiter.
Permutationen einer Tabelle sind z.B. eine Tabelle mit einer Zeile und eine Tabelle mit zwei Zeilen.
Ich verdeutliche das Vorgehen an einem Element mit zwei Kindern A und B.
Die einzelnen Kinder permutieren
Für die beiden Kinder erzeuge ich dann anhand ihrer Multiplizitäten die folgende Permutationen: Eine Menge mit zwei Kind-Mengen und eine Menge mit drei Kind-Mengen.
Die Kind-Permutationen permutieren
Dann erzeuge ich alle Kombinationen dieser zwei Kind-Mengen:
Für diese Kind-Mengen bestimme ich alle möglichen Unterbäume von A und B und multipliziere ein weiteres Mal aus.
Eine Besonderheit ist M1: Eine Menge mit zwei leeren Mengen als Elemente. Das führt zu einem Element ohne Kinder. Auch dies ist ein wichtiger Testfall.
Der Einfachheit halber zeige ich das für die Kind-Menge M5, in der genau ein A und ein B enthalten ist:
Bilden der Unterbäume für die aktuelle Permutation
Für dieses Beispiel gehe ich davon aus, dass es zwei mögliche Unterbäume von A (A1, A2) und drei mögliche Unterbäume von B (B1, B2, B3) gibt:
Die Unterbäume in das aktuelle Element einhängen
Dann erzeuge ich für jede dieser möglichen Kombinationen von Unterbäumen eine Instanz von E mit dem entsprechenden Unterbaum:
Dieses Verfahren wende ich rekursiv an um aller Permutationen der Teilbäume zu erzeugen.
Model-to-Model-Transformation mit Java
Für die Model-to-Model-Transformation verwende ich Java-Klassen statt EOL. Es war für mich eine echte Erleichterung, den Code im Debugger laufen zu lassen. Und es zeigt, wie einfach es ist, von Java aus Modelle zu lesen und zu schreiben. Und wie einfach man die Modellklassen um eigene Methoden erweitern kann.
Das eigentliche Java-Programm GenTestCases im Ordner src/main/java/flexml/gentest ist recht kurz: