Aufzählungen sind einfach endliche Typen mit benutzerdefinierten (hoffentlich aussagekräftigen) Namen. Eine Aufzählung kann nur einen Wert haben, void
der nur enthält null
(einige Sprachen nennen dies unit
und verwenden den Namen void
für eine Aufzählung ohne Elemente!). Es kann zwei Werte haben, wie bool
das hat false
und true
. Es kann drei, wie colourChannel
mit red
, green
undblue
. Und so weiter.
Wenn zwei Aufzählungen die gleiche Anzahl von Werten haben, sind sie "isomorph". dh wenn wir alle Namen systematisch austauschen, können wir einen anstelle des anderen verwenden und unser Programm wird sich nicht anders verhalten. Insbesondere verhalten sich unsere Tests nicht anders!
Zum Beispiel result
enthält win
/ lose
/ draw
ist isomorph zum oben colourChannel
, da wir ersetzen kann zB colourChannel
mit result
, red
mit win
, green
mit lose
und blue
mit draw
, und so lange , wie wir dies tun , überall (Erzeuger und Verbraucher, Parser und Serializer, Datenbankeinträge, Log - Dateien, usw. ) dann wird sich an unserem Programm nichts ändern. Alle " colourChannel
Tests", die wir geschrieben haben, werden immer noch bestehen, auch wenn es keine gibtcolourChannel
keine mehr gibt!
Wenn eine Aufzählung mehr als einen Wert enthält, können wir diese Werte jederzeit neu anordnen , um eine neue Aufzählung mit der gleichen Anzahl von Werten zu erhalten. Da sich die Anzahl der Werte nicht geändert hat, ist die neue Anordnung gegenüber der alten isomorph, sodass wir alle Namen austauschen konnten und unsere Tests weiterhin bestanden würden (beachten Sie, dass dies nicht möglich ist die Definition einfach austauschen müssen) alle nutzungsseiten auch noch ausschalten).
Dies bedeutet, dass für die Maschine Aufzählungen "unterscheidbare Namen" und nichts anderes sind . Das einzige, was wir mit einer Enumeration machen können, ist zu verzweigen, ob zwei Werte gleich (zB red
/ red
) oder verschieden (zB red
/ blue
) sind. Das ist also das einzige, was ein "Unit-Test" tun kann, z
( red == red ) || throw TestFailure;
(green == green) || throw TestFailure;
( blue == blue ) || throw TestFailure;
( red != green) || throw TestFailure;
( red != blue ) || throw TestFailure;
...
Wie @ jesm00 sagt, ein solcher Test die prüft Sprache Implementierung anstatt das Programm. Diese Tests sind niemals eine gute Idee: Auch wenn Sie der Sprachimplementierung nicht vertrauen, sollten Sie sie von außen testen , da es nicht vertrauenswürdig ist, die Tests korrekt auszuführen!
Das ist also die Theorie; was ist mit der Praxis? Das Hauptproblem bei dieser Charakterisierung von Aufzählungen ist, dass Programme der „realen Welt“ selten in sich geschlossen sind: Wir verfügen über ältere Versionen, Remote- / Embedded-Bereitstellungen, historische Daten, Backups, Live-Datenbanken usw., sodass wir nie wirklich „ausschalten“ können. Alle Vorkommen eines Namens, ohne dass Verwendungen fehlen.
Solche Dinge liegen jedoch nicht in der „Verantwortung“ der Aufzählung selbst: Das Ändern einer Aufzählung kann die Kommunikation mit einem entfernten System unterbrechen, aber umgekehrt können wir ein solches Problem durch Ändern einer Aufzählung beheben !
In solchen Szenarien ist die Enum eine rot-Hering: was passiert , wenn ein System muss es sein , diese Art und Weise, und ein anderer muss es sein , dass Art und Weise? Es kann nicht beides sein, egal wie viele Tests wir schreiben! Der eigentliche Schuldige ist hier die Eingabe- / Ausgabeschnittstelle, die wohldefinierte Formate erzeugen / konsumieren sollte und nicht "welche Ganzzahl die Interpretationsauswahl auch immer". Die eigentliche Lösung besteht also darin , die E / A-Schnittstellen zu testen : mit Komponententests, um zu überprüfen, ob das erwartete Format analysiert / gedruckt wird, und mit Integrationstests, um zu überprüfen, ob das Format tatsächlich von der anderen Seite akzeptiert wird.
Wir mögen uns immer noch fragen, ob das Enum 'gründlich genug trainiert' wird, aber in diesem Fall ist das Enum wieder ein roter Hering. Was uns eigentlich Sorgen macht, ist die Testsuite selbst . Wir können hier auf verschiedene Arten Vertrauen gewinnen:
- Die Codeabdeckung kann uns sagen, ob die Vielzahl der von der Testsuite stammenden Aufzählungswerte ausreicht, um die verschiedenen Verzweigungen im Code auszulösen. Wenn nicht, können wir Tests hinzufügen, die die nicht abgedeckten Zweige auslösen, oder eine größere Anzahl von Aufzählungen in den vorhandenen Tests generieren.
- Die Eigenschaftsprüfung kann uns sagen, ob die Vielzahl der Verzweigungen im Code ausreicht, um die Laufzeitmöglichkeiten zu handhaben. Wenn zum Beispiel der Code nur verarbeitet
red
und wir nur mit testen red
, haben wir eine 100% ige Abdeckung. Eine Eigenschaftsprüfung generiert (versucht) Gegenbeispiele zu unseren Behauptungen, wie z. B. das Generieren der Werte green
und blue
, die wir vergessen haben, zu testen.
- Mutationstests können uns sagen, ob unsere Behauptungen tatsächlich die Aufzählung überprüfen , anstatt nur den Zweigen zu folgen und ihre Unterschiede zu ignorieren.