Freitag, 20. August 2010

Wir basteln uns Test-Daten, Teil 1

Eigentlich hat man ganze Wagenladungen voller XML die ungenutzt in irgendwelchen Ordnern verstauben. Manchmal aber genügen diese Dateien nicht - man benötigt reprodurzierbare, gleichartige Dateien um Tests auf verschiedenen Systemen durchführen zu können.

Um Tests auf verschiedenen Systemen durchzuführen, müssen der Test und die Daten immer gleich sein. Allerdings möchte man auch nicht tausende von Daten auf einem USB-Stick mit sich herumtragen und über unterschiedliche Netzwerke zeitaufwendig verteilen müssen.
Die vorhandenen Wagenladungen mit alten XML-Dateien sind für Tests nicht immer geeignet: Auch wenn Daten alt sind, sollte man sie nie öffentlich zugänglich machen, besonders nicht in großer Zahl.

Eine Möglichkeit ist es Dateien vor Ort "frisch" zu generieren. PHP ist als Basis dafür ideal geeignet, da es auch ohne Installation und ohne Webserver überall ausgeführt werden kann.
Um sicherzustellen, dass die Daten immer gleich sind, müssen wir bei der Erzeugung alle Zufallsfaktoren ausschließen. Dennoch müssen sich die Inhalte von XML zu XML verläßlich unterscheiden.

Wir haben also mehrere Anforderungen:

Die Daten müssen reproduzierbar sein.
Es darf keine zufälligen Daten oder Bestandteile geben.
Sie müssen sich inhaltlich wesentlich voneinander unterscheiden.
Die Daten müssen vor Ort erstellt werden.
Die Anzahl der Daten muss immer gleich sein.
Als Datenbasis wollen wir einen bestehenden Text nehmen, der nach festen Regeln zerteilt wird. In einem zweiten Schritt werden alle entstandenen Passagen aufbereitet, zusätzliche Informationen daraus generiert und schließlich wird jede Passage mit Ihren Informationen in eine XML geschrieben.

Die einzelnen Teile wollen wir als einfaches, entwicklungsfähiges Gerüst objektorientiert umsetzen und nachdem wir bereits drei Klassen definiert haben, kommt der schwerste Teil: Namen für die Klassen finden.
Unsere Klasse, die den Text in Passagen zerteilt und bereitstellt nennen wir "TextTeiler", die Klasse die die entstandenen Absätze aufbereitet nennen wir "AbsatzInspektor" - nur "PassagenAufbereiter" würde noch schlechter klingen. Unsere Klasse zur Erzeugung der Dateien auf Basis unserer erzeugten Daten nennen wir "XMLSchreiber".
Es sollte einen Wettbewerb für schlechte Namen geben.

Damit keinerlei Missverständnisse aufkommen: Ich arbeite bewußt nicht nach der Vorstellung, dass in der OOP irgendeine Realität abgebildet werden müsse. Dies kann im Einzelfall passend sein, ist aber nicht grundsätzlich in der Programmierung empfehlenswert geschweige denn sinnvoll. Vor allem aber ist es kein zwingender Bestandteil der OOP wie oft postuliert.

Beginnen wir mit unserer Klasse "TextTeiler".

Als Quelle für Texte empfehle ich www.gutenberg.org. Gewählt habe ich unter anderem "THE SAILOR'S WORD-BOOK" von "ADMIRAL W. H. SMYTH", das als fast 2MB grosse Text-Datei in immerhin 13291 Passagen aufgeteilt wird.

Alle Variablen unserer Klasse sind als "private" deklariert, der Zugriff erfolgt ausschließlich über entsprechende Getter-Methoden. Ein schreibender Zugriff könnte die Klasse aus dem Tritt bringen und unvorhergesehene, falsche Ergebnisse liefern, da die weiteren Berechnungen von den Werten der Variablen abhängig sind.

class TextTeiler
{
//$Objekt = new TextTeiler("text.txt")
//Eine Textdatei wird gelesen und nach Absaetzen aufgebrochen
//
// $Objekt->NaechstePassage(), ein Absaetz wird ausgegeben,
//  der interne Zeiger auf den naechsten Absatz gesetzt
// $Objekt->AktuellePassage(), der aktuelle Absatz
// $Objekt->Zeiger(), die aktuelle Zeigerposition wird geliefert
// $Objekt->Absaetze(), die Anzahl aller Absaetze wird geliefert

    private $DateiInhalt = array(); private $Absaetze;
    private $AktuellePassage = ''; private $Zeiger = 0;
    private $Trenner = "/(\r\n){2,}/";


    function __construct($Datei)
    {
        if(is_file($Datei))
        {
            $Inhalt = file_get_contents($Datei);
            $this->DateiInhalt = preg_split($this->Trenner, $Inhalt);
            unset($Inhalt);
            $this->Absaetze = count($this->DateiInhalt);
        }else{die('Keine Quelldatei gefunden.');}
    }

    function NaechstePassage()
    {
        $this->AktuellePassage = $this->DateiInhalt[$this->Zeiger];
        $this->Zeiger++;
        return $this->AktuellePassage;
    }

    function AktuellePassage() {return $this->AktuellePassage;}
    function Zeiger() {return $this->Zeiger;}
    function Absaetze() {return $this->Absaetze;}

}
Die Klasse teilt den Text durch einen regulären Ausdruck nach zwei aufeinanderfolgenden Zeilenumbrüchen wie dies bei den Texten von gutenberg.org Verwendung findet. Um hier flexibel zu sein sollte hier eine Setter-Methode geschrieben werden, die einen neuen Ausdruck empfängt, überprüft und dann damit arbeitet.

Keine Kommentare:

Kommentar veröffentlichen