Java Standard: Assertions


Das Gegenstück zur Exception ist die Assertion (deutsch etwa: "Behauptung"). Mit ihr werden Programmierfehler aufgespürt und gemeldet, wenn das Programm in einem Testmodus gestartet wird. Sie werden deswegen meist an Stellen in der Programmierung eingebaut, an denen die Verarbeitung der Daten bereits erfolgt ist.

Um eine solche Überprüfung in ein Programm einzupflegen gibt es ein eigenes Schlüsselwort: assert. Es wird an einer beliebigen Stelle im Code eingebaut, gefolgt von einer Abfrage, die entweder true oder false zurückgibt. Falls diese Überprüfung positiv endet, wird das Programm fortgesetzt; andernfalls wird eine Exception ausgelöst, ein AssertionError, der eine Meldung auf dem Bildschirm ausgibt und das Programm üblicherweise an dieser Stelle beendet.

assert x>3;

An dieser Stelle wird im Programmcode die Variable x darauf getestet, dass sie einen Wert größer drei ergibt; andernfalls wird der Programmlauf mit einer Fehlermeldung abgebrochen. Weil eine solche Standard-Fehlermeldung oft zusätzliche Informationen liefern sollte, als es mit dem Standardtext der assert-Meldung möglich ist, kann man den Befehl um einen eigenen Fehlertext erweitern. Dazu wird der Teil hinter der Prüfung mit einem Doppelpunkt abgetrennt und dann die gewünschte Meldung angegeben:

assert x>3 : "Fehlerhafte Programmierung in der Funktion abc(): x < 4 und damit ungültig!";

So kann das Problem deutlich leichter eingekreist werden. Natürlich sind auch andere Fehlermeldungen denkbar, zum Beispiel die Ausgabe der Variablen selbst:

assert x>3 : x;

Auch wesentlich aufwendigere Prüfungen sind möglich, indem für die Tests beliebige Funktionen definiert werden, die als Ergebnis true oder false liefern. In diesem Fall muss aber sehr genau darauf geachtet werden, dass die Testfunktion keine Zustände des Programms beeinflusst, also Variablen innerhalb der Klasse verändert werden. Da die Prüfung im normalen Betrieb unterbleibt würde auch die Veränderung des Status der Klasse nicht vorgenommen werden, sprich: die Klasse reagiert mit Test anders als ohne Test. Solch einen Fehler aufzuspüren kostet jede Menge graue Haare.

Auf diese Weise kann man fehlerhaften Code in der Programmierung relativ leicht einkreisen. Wichtig ist, dass der Test hinter dem Schlüsselwort als Ergebnis true zurückliefert, wenn die getestete Programmierung ein korrektes Ergebnis liefert.

Aktivierung des SoftwaretestsBearbeiten

Die Verwendung des Schlüsselwortes assert hat einen zusätzlichen Vorteil: Sie kann im Code des Programmes auch dann stehen bleiben, wenn alle Softwaretests erfolgreich abgeschlossen wurden und die Software für die Benutzer freigegeben werden kann. Bei einem normalen Aufruf von Java wird das Schlüsselwort und alle damit verbundenen, möglicherweise zeitintensiven Tests bei der Ausführung komplett ignoriert. Die Tests müssen beim Aufruf des Programms ausdrücklich angeschaltet werden. Wahrscheinlich arbeiten Sie mit einer Entwicklungsumgebung; bitte suchen Sie sich hier die entsprechende Einstellung aus den Menüs heraus. Falls es keine solche Einstellung gibt oder falls Sie Java-Programme über die Kommandozeile starten, gehen Sie bitte wie folgt vor:

Unter Java Version 1.4 wird das Programm über den Compiler mit einer eigenen Option übersetzt, die die Überprüfungen einschaltet; der auszuliefernde Code muss später ohne diese Option erneut compiliert werden:

javac -source 1.4 WikiBooks

Ab Java Version 5 wird die Prüfung direkt im Interpreter vorgenommen, es bedarf also keines zusätzlichen Compilerlaufes. Das hierfür vorgesehene Flag lautet -ea (oder -enableassertations) zum Einschalten der Prüfung; dahinter wird der Name des Paketes angefügt:

java -ea WikiBooks

Eine einzelne Klasse innerhalb eines Paketes kann ebenfalls getestet werden, ohne dass dafür das komplette Paket mitgetestet wird. In diesem Fall wird hinter dem Kommandozeilenparameter -ea: (jetzt direkt hinter dem Parameter mit Doppelpunkt angefügt) der Pfad zur Klasse angegeben und dahinter das Paket genannt, in dem die Klasse zu finden ist:

java -ea:testumgebung.wikibooks.BeispielKlasse WikiBooks

Wenn in dem zu testenden Paket weitere Pakete stecken, die zu testen sind, ist auch das problemlos möglich. Dafür müssen hinter dem vollständigen Pfad nur drei Punkte angegeben werden:

java -ea:testumgebung.wikibooks...

Gelegentlich ist es sinnvoll, einzelne Teile des Paketes auszunehmen. Auch das ist mit einem Kommandozeilenparameter möglich. Er lautet -da bzw. -disableassertions und wird mit dem kompletten Pfad des auszuschließenden Teiles aufgerufen:

java -ea WikiBooks -da:testumgebung.wikibooks.BeispielKlasse

Selbstverständlich lässt sich auch hier wieder mit dem -ea-Parameter ein Teil des ausgeschlossenen Paketes doch wieder testen, indem der Parameter mit dem kompletten Pfad zu dem betreffenden Code angehängt wird.

ÜbungenBearbeiten

Alles verstanden? Zum Selbsttest gibt es hier einige Übungen. Die Lösungen dafür finden Sie hier.

1: Ein switch()-TestBearbeiten

In einem Programm finden Sie folgende switch-Anweisung:

switch (ja_nein) {
	case JA:
		this.doYes();
		break;
	case NEIN:
		this.doNo();
		break;
	default:
		assert false;

Obwohl in der assert-Anweisung kein Test vorgenommen wird funktioniert diese Anweisung ordnungsgemäß: falls die Variable ja_nein einen anderen Wert als JA oder NEIN enthält wird das Programm mit einer Fehlermeldung abgebrochen.

1.1) Erklären Sie, warum die Anweisung auch ohne einen Test die Ausführung des Programms abbricht. 1.2) Welche Fehlermeldung wird der Programmierer zu Gesicht bekommen?

2: Do it yourselfBearbeiten

Als Grundlage gegeben sei folgende Funktion, die einen Würfelwurf simulieren soll:

public int dice() {
	return (int)math.random() * 6;
}

Schreiben Sie eine Funktion public int diceTest(), die die Summe von 100 Würfen mit dieser Funktion ermittelt und zurückliefert. Stellen Sie dabei bei jedem Wurf sicher, dass eine Zahl zwischen 1 und 6 gewürfelt wird. Nutzen Sie dabei zwei Tests: Einen für Zahlen größer 6 und einen für Zahlen kleiner 1. Tatsächlich ist ein Programmabbruch durch eine der assert-Anweisungen zu erwarten. Welche?