Properties Based Testing
Millionen Testfälle automatisch generiert, statt mühsam von Hand geschrieben: Was eigenschaftsbasiertes Testen ist und wo seine Grenzen liegen.

Eigenschaftsbasiertes Testen bezeichnet eine Methode, bei der nicht einzelne Testfälle manuell geschrieben werden, sondern das System Testfälle automatisch aus beschriebenen Eigenschaften erzeugt. Drei Komponenten arbeiten zusammen: eine Modellierungssprache für Systemeigenschaften, ein Generator für Testfälle und ein Shrinker, der Fehler auf ihren genauen Ursprung reduziert.
Das Wichtigste in Kürze
- Eigenschaftsbasiertes Testen generiert Testfälle automatisch aus einer formalen Beschreibung des Systemverhaltens, statt jeden Fall manuell zu schreiben, weil die Anzahl möglicher Fehlerkombinationen in verteilten Systemen menschliche Kapazität weit übersteigt.
- Die drei Kernkomponenten des Ansatzes sind Generator, der Testfälle aus der Spezifikation erzeugt, Verifizierer, der Verstöße erkennt, und Shrinker, der eine lange Fehlerkette auf den kleinsten reproduzierbaren Schritt reduziert.
- Eigenschaftsbasiertes Testen stößt an Grenzen, wenn jeder generierte Testfall direkte Kosten verursacht, etwa durch Telefonanrufe oder Cloud-Ressourcen, weil bei Millionen automatisch erzeugter Fälle die Ausgaben außer Kontrolle geraten können.
- Das Konzept started mit dem Haskell-Framework QuickCheck und wurde in viele Sprachen portiert; für .NET, Python und andere Stacks existieren heute eigene Implementierungen, darunter auch kommerzielle Tools für sicherheitskritische Bereiche wie die Automobilindustrie.
- Die größte Hürde bei der Einführung eigenschaftsbasierter Tests ist nicht die Technik, sondern der Mentalitätswandel im Team: Ein einzelnes Pilotteam als Referenz zu gewinnen überzeugt Kolleginnen und Kollegen wirkungsvoller als jede interne Empfehlung.
Was ist eigenschaftsbasiertes Testen?
Eigenschaftsbasiertes Testen beschreibt nicht einzelne Testfälle, sondern die Eigenschaften eines Systems. Aus dieser Beschreibung generiert ein Werkzeug die konkreten Testfälle automatisch, oft Tausende oder Millionen davon.
Der Unterschied zum klassischen Vorgehen ist grundlegend. Normalerweise definierst du Eingaben und erwartete Ausgaben: Eingabe I1 ergibt Ausgabe O1, I2 ergibt O2 und so weiter. Beim eigenschaftsbasierten Testen formulierst du stattdessen eine Regel, die für jede beliebige Eingabe gelten muss.
Ein einfaches Beispiel macht das deutlich. Ein Dienst nimmt zwei Eingaben A und B und liefert die Summe C zurück. Die Eigenschaft lautet dann: Wenn man von der Ausgabe C den Wert B abzieht, muss A herauskommen. Mehr beschreibst du nicht. Das System erzeugt daraus beliebig viele Kombinationen aus A und B und prüft jede gegen diese Regel.
Genau an den Rändern wird das wertvoll. Bei bestimmten Kombinationen, die sich Grenzwerten nähern, kann es zu Puffer- oder Integer-Überläufen kommen. Ein Mensch schreibt dafür ein paar Testfälle mit null, ein, zwei, negativen und positiven Zahlen. Die generierte Variante deckt den Eingaberaum ab, den ein Tester von Hand nie vollständig durchgehen würde.
Warum verteilte Systeme nach generierten Tests verlangen
Bei großen Microservice-Landschaften übersteigt die Zahl der Fehlerkombinationen die menschliche Vorstellungskraft. Genau hier setzt eigenschaftsbasiertes Testen an.
Die Rechnung ist simpel. Bei n Diensten, bei denen ein Fehler erst entsteht, wenn zwei oder drei weitere Dienste ausfallen, liegt die Zahl der relevanten Kombinationen in der Größenordnung von n hoch 3. Bei tausend Diensten sind das Millionen von Fehlermöglichkeiten. Niemand schreibt dafür eine Million Testfälle von Hand.
Hinzu kommt die Art, wie Fehler in verteilten Systemen auftreten. Ein Dienst fällt aus, der Fehler pflanzt sich fort, und auffällig wird er erst, wenn der fünfte Server kippt. Solche Kettenreaktionen entdeckt man nur, wenn die Testfälle in großer Zahl und in unerwarteten Reihenfolgen durchgespielt werden.
Die drei Komponenten: Spezifikation, Generator, Shrinker
Eigenschaftsbasiertes Testen besteht in der Praxis aus drei Teilen, die zusammenarbeiten.
Die erste Komponente ist die Modellierungssprache oder Spezifikation. Hier beschreibst du das Verhalten und die Eigenschaften deines Systems. Im einfachsten Fall ist das eine Gleichung, in realen Systemen kommen formale Spezifikationssprachen wie TLA+ zum Einsatz.
Die zweite Komponente ist der Generator. Er nimmt die Spezifikation und schreibt daraus die Testfälle. Findet er einen Verstoß, weißt du, dass etwas nicht stimmt. Du kannst einen eigenen Generator schreiben oder einen Standardgenerator nutzen.
Die dritte Komponente ist der Shrinker, auch Reducer genannt. Generierte Testfälle laufen oft als lange Folgen von Schritten. Findet das System einen Fehler nach 17 einzelnen Schritten, hilft dir diese Information allein wenig: Du weißt nicht, welcher Schritt das Problem ausgelöst hat. Der Shrinker reduziert die Folge auf den Kern und zeigt dir, wo genau es schiefgeht.
Ein reales Beispiel zeigt die Wirkung. Bei einem Test einer Google-Datenbank trat ein Fehler erst nach 17 wiederholten Schritten auf. Eine Kombination, die kein Mensch erraten würde. Mit eigenschaftsbasiertem Testen war der Fehler innerhalb einer Stunde gefunden.
Welche Frameworks und Werkzeuge es gibt
Das Konzept ist sprach- und stackunabhängig, die Umsetzung übernehmen verschiedene Frameworks. Sie unterscheiden sich darin, wie sie Testfälle erzeugen und reduzieren.
Begonnen hat alles mit QuickCheck, einem Werkzeug aus der Sprache Haskell. Von dort wurde das Prinzip in zahlreiche Sprachen übertragen. Für .NET existiert FsCheck, für Python gibt es ebenfalls passende Bibliotheken. Es gibt sowohl kommerzielle als auch Open-Source-Varianten.
In sicherheitskritischen Bereichen wie der Automobilindustrie kommen kommerzielle Werkzeuge zum Einsatz. Dort ist die Software geschäftskritisch: Versagt sie, sterben im Zweifel Menschen. Die vollständige Abdeckung der Kombinationen dient direkt der Zuverlässigkeit.
Eigenschaften beschreiben heißt, das ganze System zu denken
Eine Eigenschaft ist eine Regel, die nach jeder Transaktion gelten muss. Sie zwingt dich, das Verhalten deines Systems präzise zu fassen.
Nimm einen Online-Shop. Kauft jemand n Tafeln Schokolade, muss der Lagerbestand vorher und nachher genau um n sinken. Gleichzeitig muss der Umsatz um den Preis dieser n Tafeln steigen. Beides sind Eigenschaften, die du dem System mitgibst.
In einem einfachen System ist das trivial und fast nie ein Problem. Reale Systeme arbeiten aber verteilt, über mehrere Datenbanken und Rechenzentren hinweg, mit Eventual Consistency. Eine Eigenschaft kann für einen Datensatz im Rechenzentrum eins zutreffen und im Rechenzentrum zwei nicht. Wie testest du diese Bedingungen? Du beschreibst die Eigenschaft, und das System schreibt die Tests dafür.
Auf welcher Ebene du spezifizierst, entscheidet über die Testart. Beschreibst du auf Dienstebene, entsteht ein Unit-Test. Beschreibst du auf Systemebene, ein Integrationstest. In der Praxis machen die meisten beides.
Verwandt, aber anders herum: TLA+ und Parallelität
Formale Methoden lösen ein verwandtes Problem von der Entwurfsseite her, während eigenschaftsbasiertes Testen fertige Software prüft. Der Kerngedanke ist derselbe.
Parallele Systeme mit Threads und Locks haben eine unangenehme Eigenheit: Fehler treten nur sporadisch auf. Unit-Tests laufen durch, Integrationstests laufen durch, in Produktion läuft zwei Monate alles glatt. Am ersten Tag des dritten Monats kippt das System, weil eine bestimmte Kombination äußerer Bedingungen eingetreten ist.
TLA+ adressiert das, indem es ein Zustandsraumdiagramm aller möglichen Abläufe und Kombinationen aufspannt. Daraus lässt sich erkennen, wo ein Thread-Deadlock entsteht oder welches Parallelitätsproblem droht. Manchmal ist die Konsequenz, dass ein Teil des Systems neu entworfen werden muss, weil ein grundlegendes Designproblem vorliegt. Amazon AWS nutzt diese Methode und hat darüber öffentlich publiziert.
Wann eigenschaftsbasiertes Testen nicht passt
Die Grenze liegt bei Tests, die destruktiv sind oder reale Ressourcen verbrauchen. Wenn jeder Testfall Geld kostet, gerät die automatische Generierung von Millionen Fällen außer Kontrolle.
Zwei Beispiele zeigen das Problem. Bei Telefonie löst ein Test einen echten Anruf aus. Eine Million Testfälle bedeuten eine Million Anrufe und eine entsprechend hohe Rechnung. Genauso verhält es sich in der Cloud: Schreibt dein Test auf Speichermedien, werden dir alle dabei genutzten Ressourcen berechnet. Bei automatisch generierten Massen an Testfällen explodieren die Kosten.
In solchen Fällen ist eigenschaftsbasiertes Testen die falsche Wahl. Die Stärke der Methode, beliebig viele Fälle zu erzeugen, wird hier zum finanziellen Risiko.
So fängst du an: klein starten, organisch wachsen
Der wichtigste Rat ist einfach: Fang mit einem Dienst an und erweitere dann Schritt für Schritt. Das gilt nicht nur für eigenschaftsbasiertes Testen, sondern für jede neue Methode.
Probier die Methode an einem überschaubaren Teil deines verteilten Systems aus und schau, wie gut sie funktioniert. Wächst sie organisch, zeigen sich Risiken und Hindernisse früh. Das ist die agile Idee vom schnellen Scheitern. Funktioniert das Werkzeug bei einem Dienst, funktioniert es wahrscheinlich auch beim nächsten.
Quellen findest du heute reichlich. In Büchern und im Netz gibt es zu fast jedem Framework Erfahrungsberichte und Empfehlungen. Informationen sind kein Engpass mehr.
Eine neue Methode einzuführen ist Verkaufsarbeit, nicht Programmierarbeit
Der schwierigste Teil ist nicht der Code, sondern die Menschen davon zu überzeugen. Ein neues Werkzeug verlangt einen Mentalitätswandel, und der ist in einer großen Belegschaft schwer durchzusetzen.
Das Schwierigste an meinem Job ist, die Leute davon zu überzeugen, etwas zu tun. Und das sind Leute, die wie ich zwanzig Jahre Erfahrung haben. — Nikhil Barthwal
Erfahrung kann ein Hindernis sein. Wer lange dabei ist, weiß genau, wie er arbeitet, und reagiert skeptisch auf neue Tools. Nikhil hat das erlebt, als er ein neues Build-System baute, es allen vorführte und niemand es benutzte.
Sein Ansatz: Such dir bei fünfzig Teams ein einzelnes, das bereit ist mitzumachen. Zeig dort den konkreten Nutzen und lass dieses Team den Wert an die anderen weitertragen. Bei der Einführung einer Technologie bist du Verkäufer, deine Entwickler sind die Kunden. Eine Empfehlung von einem anderen Team wiegt schwerer als jedes Eigenlob, weil beim Anbieter immer ein Interessenkonflikt mitschwingt.
Wie du generierten Tests vertraust
Eigenschaftsbasiertes Testen ersetzt den Tester nicht, es unterstützt ihn. Wenn ein generierter Testfall fehlschlägt, bekommst du die vollständige Abfolge der Ereignisse und kannst prüfen, ob der Fehler echt ist.
Das ist die Antwort auf das Vertrauensproblem. Bei selbst entworfenen Testfällen kennst du jeden Schritt. Bei Millionen generierten Kombinationen siehst du nicht alles, aber das System filtert für dich. Aus einer Million möglicher Fehler bleiben vielleicht zwanzig konkrete Fälle übrig, auf die du dich konzentrierst.
Falsch-negative Ergebnisse kommen vor. Oft liegt der eigentliche Fehler dann in der Art, wie du dein System beschrieben hast. Deshalb braucht es menschliche Aufsicht: Du musst verstehen, was passiert ist, bevor du es reparierst. Hier liefert der Shrinker die Vorarbeit, indem er dir genau zeigt, wo es schiefging.
Die Parallele zur KI-Debatte liegt nahe. Eigenschaftsbasiertes Testen ersetzt den Tester nicht, es macht ihn produktiver. Genau das ist sein Versprechen.
Ähnliche Beiträge

Richard Seidl
•2. Juni 2026
Patient Agilität: Liegt agiles Arbeiten im Sterben?

Richard Seidl
•26. Mai 2026