Assertion
Eine Zusicherung oder Assertion (lat./engl. für Aussage; Behauptung) ist eine Aussage über die Variablen eines Computer-Programmes.Bei einer Assertion wird davon ausgegangen, dass die in ihr definierte Bedingung zur Laufzeit des Programms stets wahr ist. Sollte dies nicht der Fall sein, kann von einem Programmfehler ausgegangen werden. Damit unterscheiden sie sich von der klassischen Fehlerkontrolle durch Kontrollstrukturen oder Ausnahmen (Exceptions), die einen Fehlerfall als mögliches Ergebnis einschließen. In einigen Programmiersprachen stellen Assertions eine Sonderform der Ausnahmen dar.
Eingeführt wurde dieser Begriff von Robert Floyd 1967 in seinem Artikel Assigning Meanings to Programs. Er schlug eine Methode vor, mit der man die Korrektheit von Flussdiagrammen beweisen konnte indem man jedes Element des Flussdiagramms mit einer Zusicherung versieht. Floyd gab Regeln an, nach denen die Zusicherungen bestimmt werden konnten. Tony Hoare entwickelte diese Methode zum Hoare-Kalkül für prozedurale Programmiersprachen weiter. Im Hoare-Kalkül wird eine Zusicherung, die vor einer Anweisung steht, Vorbedingung (engl. precondition), eine Zusicherung nach einer Anweisung Nachbedingung (engl. postcondition) genannt. Eine Zusicherung, die bei jedem Schleifendurchlauf erfüllt sein muss, heißt Invariante.
Niklaus Wirth benutzte Zusicherungen zur Definition der Semantik von Pascal und schlug vor, dass Programmierer in ihre Programme Kommentare mit Zusicherungen schreiben sollten. Aus diesem Grund sind Kommentare in Pascal mit geschweiften Klammern {...} umgeben, eine Syntax, die Hoare in seinem Kalkül für Zusicherungen verwendet hatte.
In der Programmiersprache C können Zusicherungen als Anweisungen geschrieben werden. Zum Beispiel:
assert(pointer != NULL);
Beim Übersetzen kann eingestellt werden, ob Zusicherungen zur Laufzeit überprüft werden. Eine Version mit Überprüfung der Zusicherungen kann zum Debuggen benutzt werden. Die ausgelieferte Version kann dann leicht ohne Überprüfungen erstellt werden und hat daher geringere Laufzeit. Allerdings birgt dieses Verfahren die Gefahr, dass das Programm durch Weglassen der Zusicherungen auch seine Funktionsweise verändert.
Die Zusicherungen können unbeabsichtigte Nebeneffekte in einem Programm verursachen:
// falls die Zusicherungen abgeschaltet werden, wird die Funktion
// BerechneSteuerSatz nicht mehr aufgerufen
// dadurch ändert sich der Programmablauf
assert(BerechneSteuerSatz(betrag, steuer1, steuer2)
true);
// oder kurz
assert(BerechneSteuerSatz(betrag, steuer1, steuer2));
Nimmt der überprüfte Ausdruck einer Assertion den Wert false an, wird das Programm unter Umständen sofort beendet. Meistens wird die Quelldatei und die Zeilennummer genannt, an der die Zusicherung nicht erfüllt wurde.
Java kennt das Konzept der Zusicherungen ab Version 1.4. Hier wird allerdings das Programm nicht notwendigerweise beendet, sondern eine so genannte Ausnahme (englisch exception) geworfen, die innerhalb des Programms weiter verarbeitet werden kann.
Ein einfaches Beispiel einer Assertion (hier in Java-Syntax) ist
int n = readInput();
n = n * n; //Quadrieren
assert n >= 0;
Mit dieser Assertion sagt der Programmierer "Ich bin mir sicher, dass nach dieser Stelle n größer gleich null ist".
Bertrand Meyer hat die Idee von Zusicherungen in dem Programmierparadigma Design by Contract verarbeitet und in der Programmiersprache Eiffel umgesetzt. Vorbedingungen werden durch require-Klauseln, Nachbedingungen durch ensure-Klauseln beschrieben. Für Klassen können Invarianten spezifiziert werden. Auch in Eiffel werden Ausnahmen geworfen, wenn eine Zusicherung nicht erfüllt ist.
Assertionen zur Kompilierzeit
Während die oben beschriebenen Assertionen zur Laufzeit des Programms geprüft werden, gibt es in C++ die Möglichkeit, Bedingungen auch schon beim Übersetzen des Programms durch den Compiler zu überprüfen. Es können nur Bedingungen nachgeprüft werden, die zur Übersetzungszeit bekannt sind, z. B.
sizeof(int) 4. Schlägt ein Test fehl, lässt sich das Programm nicht übersetzen. Eine entsprechende Funktion BOOST_STATIC_ASSERT befindet sich in der Bibliothek Boost.Testgetriebene Entwicklung
Ein Paradigma, in dem Zusicherungen eine Rolle spielen, ist die Testgetriebene Entwicklung, die zum Beispiel als Teil des Extreme Programmings durchgeführt wird. Vor Implementierung einer Funktionalität werden hier Tests geschrieben, in denen Methoden einzeln oder hintereinander ausgeführt werden. Zur Überprüfung des erwarteten Ergebnisses werden Zusicherungen überprüft und bei Nichterfüllung der entsprechende Test als nicht bestanden gemeldet.
Beim unit testing wird Code, der zum Testen von Funktionen und Methoden verwendet wird, in eigene Dateien (sog. Units) ausgelagert.
Diese Strategie wird von der von Kent Beck und Erich Gamma entwickelten xUnit-Testframework-Familie unterstützt (z. B. JUnit, SUnit).
Verwandte Techniken
Neben Assert wird häufig auch Verify verwendet. Verify führt die Bedingung immer aus, gleichgültig, ob mit oder ohne Debug-Absicht kompiliert wurde. Die Überprüfung findet aber nur in der Debug-Variante statt.
// die Variable anzahl wird immer erhöht
Verify(++anzahl>2);
Assert_Valid wird eingesetzt, um Objekte auf ihre Gültigkeit zu testen. Dazu gibt es in der Basisklasse der Objekthierarchie die virtuelle Methode
AssertValid(). Die Methode sollte für jede konkrete Klasse überschrieben werden, um die internen Felder der Klasse auf Gültigkeit zu testen.// Example for CObject::AssertValid.
void CAge::AssertValid() const
{
CObject::AssertValid();
ASSERT( m_years > 0 );
ASSERT( m_years < 105 );
}
Weblinks
• Assertions in Java 5.0
Literatur
* Robert W. Floyd: Assigning meanings to programs, Proceedings of Symposia in Applied Mathematics, Volume 19 (1967), Seite 19-32

