Unittests für Methoden der Framework Factory

Sämtliche Methoden der Factory sind mockfähig, d.h., über eine Attrappe aufrufbar

Methoden der Factory

Charakteristisch für die Factory ist, dass jede Methode in eine einzelne Datei ausgelagert und der Namen der Methode im Dateinamen abgebildet wird. Damit ist das Nachladen von ausgelagertem CODE automatisierbar über Perls AUTOLOAD-Meachnismus.

Wesentlich darüber hinaus ist, dass in diesen Dateien keine package definiert wird. Genau dieser Verzicht auf die package-Deklaration ermöglicht die Wiederverwendbarkeit der Methode über Instanzen anderer Klassen. Jede Methode der Factory kann also über beliebige Instanzen beliebiger Klassen aufgerufen werden und damit auch über eine Attrappe (Mock).

# Dateiname param.pm
use xCGI;

sub param{
    my $self = shift;
    $self->{CGI} = xCGI->new() unless defined $self->{CGI};
    return $self->{CGI}->param(@_);
};

1;

Würde über der Methode eine package definiert, wäre diese nur noch über die der Package entsprechenden Instanz aufrufbar. Betrachten wir nun, wie in dem speziellen Fall ein Unit-Test ablaufen könnte. Die Aufgabe der param()-Methode besteht im Parsen von HTTP-Request-Parametern, die ein Webserver der für CGI/1.1 konfiguriert ist, in die Serverumgebung setzt, letzeres wird für den Test simuliert. Der zu erwartende Content-Type muss nicht gesetzt werden, da es dafür einen Default gibt: application/x-www-form-urlencoded

Ablauf eines Unittests

Der Test erfasst mehrere Prüfungen die im Ablauf zu finden sind, geprüft wird:

Aufgerufen wird die Methode über eine Instanz der Klasse Mock, der Ablauf ist untenstehend vereinfacht dargestellt:

# Zu konfigurieren wäre
    # Testvorbereitung, Parameter setzen
    $ENV{QUERY_STRING} = q(mock=123);

    # Name der zu testenden Methode
    my $name = 'param';

    # zu setzen wäre noch der Pfad
    # zum Verzeichnis mit der Factory
    use lib qw(/home/lib/factory);

# Unit Test Ablauf
    # Mock erstellen
    my $mock = bless{};

    # gewünschte methode compilieren
    # das wäre der erste Test
    require "$name.pm";

    # Prüfe ob die Methode verfügbar ist
    if( my $code = $mock->can($name) ) {
        # Prüfung auf das Test Kriterium
        if( $mock->$code('mock') == 123 ){
            print "Methode $name funktional";
        }
    }
    else{
        die "Die zu prüfende Methode konnte nicht gefunden werden";
    }

Lazy Delegation

Das Beispiel einer in die Factory ausgelagerten Methode ist gleichermaßen auch ein Beispiel für Lazy Delegation. In Fakt wird eine weitere Klasse xCGI eingebunden und eine Instanz dieser Klasse in eine eigene Property gesetzt. Die Methode, welche die Instanz der Klasse xCGI mitbringt, wird als eine gleichnamige Methode der eigenen Klasse delegiert. Das implementiert praktisch eine späte Dependency Injection wobei die Abhängigkeit nicht außerhalb der eigenen Klasse hergestellt wird, sondern in einer eigenen Methode.

Dependency Injection

Die Abhängigkeit wird außerhalb der Klasse hergestellt und die Instanz in den Konstruktor zur eigenen Klasse übergeben. Beim direkten Erstellen eines Mock-Objekts in einer beliebigen Package sähe das so aus, nur um das Prinzip zu verdeutlichen:

use xCGI;

# Abhängigkeit erstellen
# weitere Argumente sind hier möglich
my $cgi = xCGI->new( %options );

# Mock erstellen und Abhängikeit injezieren
my $mock = bless{ CGI => $cgi };

Danach hat der Test einen Verlauf wie obenstehend. Dadurch dass die CGI-Property bereits vorhanden ist, wird sie in der aufzurufenden Methode nicht noch einmal neu erstellt.

CGI/1.1 oder Emulation

CGI/1.1 definiert eine Schittstelle die %ENV (Serverumgebung) und STDIN/STDOUT benutzt. Wenn da was getestet werden soll, müssen Dummy-Daten auch da bereitgestellt werden wo sie entsprechend $ENV{CONTENT_TYPE} geparst werden sollen und je nach $ENV{CONTENT_LENGTH} überhaupt zu erwarten sind, also entweder in STDIN oder in %ENV. Die Daten sind aus STDIN zu lesen wenn der Request einen Header Content-Length sendet, so stehts im RFC. Laut Spezifikation CGI/1.1 setzt der Webserver diesen Requestheader in die die Serverumgebungsvariable CONTENT_LENGTH.

Transparent wie HTTP benutzbar ist, kann man Unittests selbstverständlich auch über HTTP schleifen. Das setzt natürlich ein Framework voraus, was Unittests via HTTP unterstützt. Mein Framework unterstützt das.


Anbieter: nmq​rstx-18­@yahoo.de, die Seite verwendet funktionsbedingt einen Session-Cookie und ist Bestandteil meines nach modernen Aspekten in Perl entwickelten Frameworks.