In meinem aktuellen Projekt geht es kurz gesagt um die Schaffung von "zwangsläufig zufälligen Ereignissen". Grundsätzlich erstelle ich einen Inspektionsplan. Einige von ihnen basieren auf strengen Zeitplanbeschränkungen. Sie führen einmal pro Woche am Freitag um 10:00 Uhr eine Inspektion durch. Andere Inspektionen sind "zufällig"; Es gibt grundlegende konfigurierbare Anforderungen wie "Eine Inspektion muss dreimal pro Woche stattfinden", "Die Inspektion muss zwischen 9 und 21 Uhr stattfinden" und "Es sollten nicht zwei Inspektionen innerhalb desselben Zeitraums von 8 Stunden stattfinden" Unabhängig von den Einschränkungen, die für einen bestimmten Satz von Inspektionen konfiguriert wurden, sollten die resultierenden Daten und Zeiten nicht vorhersehbar sein.
Unit-Tests und TDD (IMO) sind in diesem System von großem Wert, da sie verwendet werden können, um es schrittweise zu erstellen, während die gesamten Anforderungen noch unvollständig sind weiß momentan nicht was ich brauche. Die strengen Zeitpläne waren für TDD ein Kinderspiel. Es fällt mir jedoch schwer zu definieren, was ich teste, wenn ich Tests für den zufälligen Teil des Systems schreibe. Ich kann behaupten, dass alle vom Scheduler erzeugten Zeiten innerhalb der Beschränkungen liegen müssen, aber ich könnte einen Algorithmus implementieren, der alle derartigen Tests besteht, ohne dass die tatsächlichen Zeiten sehr "zufällig" sind. Genau das ist passiert. Ich fand ein Problem, bei dem die Zeiten, obwohl nicht genau vorhersehbar, in eine kleine Teilmenge der zulässigen Datums- / Zeitbereiche fielen. Der Algorithmus hat immer noch alle Behauptungen bestanden, die ich vernünftigerweise machen konnte, und ich konnte keinen automatisierten Test entwerfen, der in dieser Situation fehlschlagen würde, sondern bestand, wenn "zufälligere" Ergebnisse gegeben wurden. Ich musste nachweisen, dass das Problem behoben wurde, indem einige vorhandene Tests so umstrukturiert wurden, dass sie sich mehrmals wiederholen. Außerdem musste ich visuell überprüfen, ob die generierten Zeiten innerhalb des zulässigen Bereichs lagen.
Hat jemand Tipps zum Entwerfen von Tests, die nicht deterministisches Verhalten erwarten sollten?
Vielen Dank an alle für die Vorschläge. Die Hauptmeinung scheint zu sein, dass ich einen deterministischen Test brauche, um deterministische, wiederholbare und durchsetzbare Ergebnisse zu erhalten . Macht Sinn.
Ich habe eine Reihe von "Sandbox" -Tests erstellt, die Kandidatenalgorithmen für den Einschränkungsprozess enthalten (der Prozess, bei dem ein beliebig langes Byte-Array zu einer Länge zwischen einem Minimum und einem Maximum wird). Ich führe diesen Code dann durch eine FOR-Schleife, die dem Algorithmus mehrere bekannte Bytearrays (Werte von 1 bis 10.000.000, nur um zu beginnen) gibt und den Algorithmus jeweils auf einen Wert zwischen 1009 und 7919 einschränkt (ich verwende Primzahlen, um sicherzustellen, dass ein Der Algorithmus würde keine zufällige GCF zwischen dem Eingangs- und dem Ausgangsbereich passieren. Die resultierenden eingeschränkten Werte werden gezählt und ein Histogramm erstellt. Um zu "bestehen", müssen alle Eingaben im Histogramm wiedergegeben werden (um sicherzustellen, dass wir keine verloren haben), und der Unterschied zwischen zwei Buckets im Histogramm darf nicht größer als 2 sein (er sollte tatsächlich <= 1 sein) , aber bleib dran). Der Gewinnalgorithmus kann, falls vorhanden, direkt in den Produktionscode eingefügt und ein permanenter Test für die Regression durchgeführt werden.
Hier ist der Code:
private void TestConstraintAlgorithm(int min, int max, Func<byte[], long, long, long> constraintAlgorithm)
{
var histogram = new int[max-min+1];
for (int i = 1; i <= 10000000; i++)
{
//This is the stand-in for the PRNG; produces a known byte array
var buffer = BitConverter.GetBytes((long)i);
long result = constraintAlgorithm(buffer, min, max);
histogram[result - min]++;
}
var minCount = -1;
var maxCount = -1;
var total = 0;
for (int i = 0; i < histogram.Length; i++)
{
Console.WriteLine("{0}: {1}".FormatWith(i + min, histogram[i]));
if (minCount == -1 || minCount > histogram[i])
minCount = histogram[i];
if (maxCount == -1 || maxCount < histogram[i])
maxCount = histogram[i];
total += histogram[i];
}
Assert.AreEqual(10000000, total);
Assert.LessOrEqual(maxCount - minCount, 2);
}
[Test, Explicit("sandbox, does not test production code")]
public void TestRandomizerDistributionMSBRejection()
{
TestConstraintAlgorithm(1009, 7919, ConstrainByMSBRejection);
}
private long ConstrainByMSBRejection(byte[] buffer, long min, long max)
{
//Strip the sign bit (if any) off the most significant byte, before converting to long
buffer[buffer.Length-1] &= 0x7f;
var orig = BitConverter.ToInt64(buffer, 0);
var result = orig;
//Apply a bitmask to the value, removing the MSB on each loop until it falls in the range.
var mask = long.MaxValue;
while (result > max - min)
{
mask >>= 1;
result &= mask;
}
result += min;
return result;
}
[Test, Explicit("sandbox, does not test production code")]
public void TestRandomizerDistributionLSBRejection()
{
TestConstraintAlgorithm(1009, 7919, ConstrainByLSBRejection);
}
private long ConstrainByLSBRejection(byte[] buffer, long min, long max)
{
//Strip the sign bit (if any) off the most significant byte, before converting to long
buffer[buffer.Length - 1] &= 0x7f;
var orig = BitConverter.ToInt64(buffer, 0);
var result = orig;
//Bit-shift the number 1 place to the right until it falls within the range
while (result > max - min)
result >>= 1;
result += min;
return result;
}
[Test, Explicit("sandbox, does not test production code")]
public void TestRandomizerDistributionModulus()
{
TestConstraintAlgorithm(1009, 7919, ConstrainByModulo);
}
private long ConstrainByModulo(byte[] buffer, long min, long max)
{
buffer[buffer.Length - 1] &= 0x7f;
var result = BitConverter.ToInt64(buffer, 0);
//Modulo divide the value by the range to produce a value that falls within it.
result %= max - min + 1;
result += min;
return result;
}
... und hier sind die Ergebnisse:
Die LSB-Zurückweisung (Bitverschiebung der Zahl, bis sie in den Bereich fällt) war aus einem sehr einfach zu erklärenden Grund SCHRECKLICH. Wenn Sie eine Zahl durch 2 teilen, bis sie kleiner als ein Maximum ist, beenden Sie sie, sobald dies der Fall ist, und für jeden nicht trivialen Bereich werden die Ergebnisse in Richtung des oberen Drittels verschoben (wie in den detaillierten Ergebnissen des Histogramms zu sehen war) ). Dies war genau das Verhalten, das ich von den fertigen Daten aus gesehen habe; Alle Zeiten waren nachmittags, an ganz bestimmten Tagen.
MSB-Zurückweisung (Entfernen des höchstwertigen Bits von der Nummer eins zu einem Zeitpunkt, bis es innerhalb des Bereichs liegt) ist besser, aber auch hier ist es nicht gleichmäßig verteilt, da Sie mit jedem Bit sehr große Zahlen abhacken. Es ist unwahrscheinlich, dass Sie am oberen und unteren Ende Zahlen erhalten, sodass Sie eine Tendenz zum mittleren Drittel haben. Das mag jemandem zugute kommen, der Zufallsdaten in eine glockenhafte Kurve "normalisieren" möchte, aber eine Summe von zwei oder mehr kleineren Zufallszahlen (ähnlich wie beim Würfeln) würde eine natürlichere Kurve ergeben. Für meine Zwecke scheitert es.
Der einzige, der diesen Test bestand, war die Einschränkung durch Modulo-Division, die sich auch als die schnellste der drei herausstellte. Modulo wird nach seiner Definition bei den verfügbaren Eingaben eine möglichst gleichmäßige Verteilung erzeugen.
quelle
Antworten:
Was Sie hier tatsächlich testen möchten, ist vermutlich, dass der Rest Ihrer Methode bei bestimmten Ergebnissen des Randomisierers korrekt ausgeführt wird.
Wenn es das ist, wonach Sie suchen, dann verspotten Sie den Zufallsgenerator, um ihn im Rahmen des Tests deterministisch zu machen.
Ich habe im Allgemeinen Scheinobjekte für alle Arten von nicht deterministischen oder unvorhersehbaren Daten (zum Zeitpunkt des Schreibens des Tests), einschließlich GUID-Generatoren und DateTime.Now.
Bearbeiten, aus Kommentaren: Sie müssen den PRNG (dieser Begriff ist mir letzte Nacht entgangen) auf der niedrigstmöglichen Ebene verspotten - dh. wenn es das Array von Bytes generiert, nicht nachdem Sie diese in Int64s verwandeln. Oder sogar auf beiden Ebenen, sodass Sie testen können, ob Ihre Konvertierung in ein Array von Int64 wie beabsichtigt funktioniert, und dann separat testen können, ob Ihre Konvertierung in ein Array von DateTimes wie beabsichtigt funktioniert. Wie Jonathon sagte, können Sie das einfach tun, indem Sie ihm einen festgelegten Startwert geben, oder Sie können ihm das Array von Bytes geben, die zurückgegeben werden sollen.
Ich bevorzuge letzteres, weil es nicht kaputt geht, wenn sich die Framework-Implementierung eines PRNG ändert. Ein Vorteil bei der Vergabe des Startwerts ist jedoch, dass Sie, wenn Sie in der Produktion einen Fall finden, der nicht wie beabsichtigt funktioniert hat, nur eine Nummer protokollieren müssen, um ihn replizieren zu können, und nicht das gesamte Array.
Trotzdem müssen Sie bedenken, dass es aus einem bestimmten Grund ein Pseudo- Zufallszahlengenerator ist. Es kann sogar auf dieser Ebene eine gewisse Voreingenommenheit geben.
quelle
Das wird sich nach einer dummen Antwort anhören, aber ich werde es da rausschmeißen, weil ich es so gesehen habe:
Entkoppeln Sie Ihren Code vom PRNG - übergeben Sie den Startwert für die Randomisierung an den gesamten Code, der die Randomisierung verwendet. Dann können Sie die Arbeitswerte aus einem einzelnen Samen bestimmen (oder aus mehreren Samen, bei denen Sie sich besser fühlen würden). Auf diese Weise können Sie Ihren Code angemessen testen, ohne sich auf das Gesetz der großen Zahlen verlassen zu müssen.
Es klingt verrückt, aber so macht es das Militär (entweder das oder sie benutzen eine 'zufällige Tabelle', die überhaupt nicht zufällig ist)
quelle
"Ist es zufällig (genug)?" Stellt sich als unglaublich subtile Frage heraus. Die kurze Antwort lautet: Ein herkömmlicher Komponententest reicht nicht aus - Sie müssen eine Reihe von Zufallswerten generieren und sie verschiedenen statistischen Tests unterziehen, die Ihnen die Gewissheit geben, dass sie für Ihre Anforderungen zufällig genug sind.
Es wird ein Muster geben - wir verwenden schließlich Pseudozufallszahlengeneratoren. Aber irgendwann werden die Dinge "gut genug" für Ihre Anwendung sein (wo gut genug eine Menge zwischen den einzelnen Spielen an einem Ende variiert, wo relativ einfache Generatoren ausreichen, bis hin zur Kryptographie, wo man wirklich Sequenzen braucht, die nicht bestimmbar sind) von einem entschlossenen und gut ausgerüsteten Angreifer).
Weitere Informationen finden Sie im Wikipedia-Artikel http://en.wikipedia.org/wiki/Randomness_tests .
quelle
Ich habe zwei Antworten für Sie.
=== ERSTE ANTWORT ===
Sobald ich den Titel Ihrer Frage sah, kam ich, um die Lösung vorzuschlagen. Meine Lösung war die gleiche wie die, die mehrere andere vorgeschlagen haben: Ihren Zufallszahlengenerator zu verspotten. Immerhin habe ich verschiedene Programme erstellt, die diesen Trick benötigten, um gute Komponententests zu schreiben, und ich habe damit begonnen, den spöttischen Zugriff auf Zufallszahlen zu einer Standardpraxis in meiner gesamten Codierung zu machen.
Aber dann habe ich deine Frage gelesen. Und für das spezielle Problem, das Sie beschreiben, ist das nicht die Antwort. Ihr Problem bestand nicht darin, dass Sie einen Prozess vorhersehbar machen mussten, der Zufallszahlen verwendete (damit er testbar wäre). Vielmehr bestand Ihr Problem darin, zu überprüfen, ob Ihr Algorithmus die gleichmäßig zufällige Ausgabe Ihres RNG auf die von Ihrem Algorithmus ausgegebenen RNGs innerhalb der Einschränkungen abbildet. Wenn das zugrunde liegende RNG einheitlich wäre, würde dies zu gleichmäßig verteilten Inspektionszeiten führen (vorbehaltlich der problematische Randbedingungen).
Das ist ein sehr schwieriges (aber ziemlich genau definiertes) Problem. Was bedeutet, dass es ein interessantes Problem ist. Sofort fielen mir einige wirklich gute Ideen zur Lösung dieses Problems ein. Als ich noch ein heißer Programmierer war, hätte ich vielleicht angefangen, etwas mit diesen Ideen zu machen. Aber ich bin kein Hotshot-Programmierer mehr ... Ich mag es, dass ich jetzt erfahrener und erfahrener bin.
Anstatt mich auf das schwierige Problem einzulassen, dachte ich mir: Was ist der Wert davon? Und die Antwort war enttäuschend. Ihr Fehler wurde bereits behoben, und Sie werden sich in Zukunft um dieses Problem bemühen. Externe Umstände können das Problem nicht auslösen, nur Änderungen an Ihrem Algorithmus. Der EINZIGE Grund, dieses interessante Problem anzugehen, bestand darin, die Praktiken von TDD (Test Driven Design) zu erfüllen. Wenn ich eines gelernt habe, ist es, dass das blinde Festhalten an einer Übung, die nicht wertvoll ist, Probleme verursacht. Mein Vorschlag ist folgender: Schreiben Sie einfach keinen Test dafür und fahren Sie fort.
=== ZWEITE ANTWORT ===
Wow ... was für ein cooles Problem!
Sie müssen hier einen Test schreiben, der bestätigt, dass Ihr Algorithmus zur Auswahl von Inspektionsdaten und -zeiten eine gleichmäßig verteilte Ausgabe (innerhalb der Problembeschränkungen) liefert, wenn der von ihm verwendete RNG gleichmäßig verteilte Zahlen erzeugt. Hier finden Sie verschiedene Ansätze, sortiert nach Schwierigkeitsgrad.
Sie können rohe Gewalt anwenden. Führen Sie den Algorithmus einfach ein paar Mal aus, mit einem echten RNG als Eingabe. Überprüfen Sie die Ausgabeergebnisse, um festzustellen, ob sie gleichmäßig verteilt sind. Ihr Test muss fehlschlagen, wenn die Verteilung um mehr als einen bestimmten Schwellenwert von der vollkommenen Gleichmäßigkeit abweicht. Um sicherzustellen, dass Sie Probleme feststellen, kann der Schwellenwert nicht ZU niedrig eingestellt werden. Das bedeutet, dass Sie eine GROSSE Anzahl von Läufen benötigen, um sicherzugehen, dass die Wahrscheinlichkeit eines falschen Positivs (eines zufälligen Testfehlers) sehr gering ist (gut <1% für eine mittelgroße Codebasis; noch weniger für eine große Code-Basis).
Betrachten Sie Ihren Algorithmus als eine Funktion, die die Verkettung aller RNG-Ausgaben als Eingabe verwendet und dann Inspektionszeiten als Ausgabe erzeugt. Wenn Sie wissen, dass diese Funktion stückweise fortlaufend ist, können Sie Ihre Eigenschaft auf eine Weise testen. Ersetzen Sie das RNG durch ein nachahmbares RNG und führen Sie den Algorithmus mehrmals aus, um eine gleichmäßig verteilte RNG-Ausgabe zu erzielen. Wenn für Ihren Code also 2 RNG-Aufrufe erforderlich sind, die sich jeweils im Bereich von [0..1] befinden, kann der Test den Algorithmus 100-mal ausführen und die Werte [(0.0.0.0), (0.0.0.1), (0.0, 0,2), ... (0,0,0,9), (0,1,0,0), (0,1,0,1), ... (0,9,0,9)]. Dann können Sie prüfen, ob die Leistung der 100 Läufe (ungefähr) gleichmäßig im zulässigen Bereich verteilt war.
Wenn Sie den Algorithmus WIRKLICH auf zuverlässige Weise überprüfen müssen und keine Annahmen über den Algorithmus treffen ODER nicht häufig ausführen können, können Sie das Problem trotzdem angreifen, müssen jedoch möglicherweise einige Einschränkungen in Bezug auf die Programmierung des Algorithmus beachten . Schauen Sie sich als Beispiel PyPy und seinen Object Space- Ansatz an. Sie könnten einen Objektraum erstellen, der statt des eigentlichen Ausführens des Algorithmus lediglich die Form der Ausgabeverteilung berechnet (vorausgesetzt, die RNG-Eingabe ist einheitlich). Dies setzt natürlich voraus, dass Sie ein solches Tool erstellen und Ihr Algorithmus in PyPy oder einem anderen Tool erstellt ist, mit dem es einfach ist, drastische Änderungen am Compiler vorzunehmen und den Code zu analysieren.
quelle
Ersetzen Sie für die Komponententests den Zufallsgenerator durch eine Klasse, die vorhersagbare Ergebnisse für alle Eckfälle generiert . Das heißt, Sie müssen sicherstellen, dass Ihr Pseudo-Randomizer mehrmals hintereinander den niedrigstmöglichen und den höchstmöglichen Wert sowie das gleiche Ergebnis generiert.
Sie möchten nicht, dass Ihre Komponententests beispielsweise einzelne Fehler übersehen, die auftreten, wenn Random.nextInt (1000) 0 oder 999 zurückgibt.
quelle
Vielleicht möchten Sie einen Blick auf Sevcikova et al. Werfen: "Automatisiertes Testen stochastischer Systeme: Ein statistisch fundierter Ansatz" ( PDF ).
Die Methodik ist in verschiedenen Testfällen für die UrbanSim- Simulationsplattform implementiert .
quelle
Ein einfacher Histogrammansatz ist ein guter erster Schritt, reicht jedoch nicht aus, um die Zufälligkeit zu beweisen. Für ein einheitliches PRNG würden Sie (zumindest) auch ein zweidimensionales Streudiagramm erstellen (wobei x der vorherige Wert und y der neue Wert ist). Diese Handlung sollte auch einheitlich sein. Dies ist in Ihrer Situation kompliziert, da das System absichtliche Nichtlinearitäten aufweist.
Mein Ansatz wäre:
Jeder dieser Tests ist statistisch und erfordert eine große Anzahl von Stichprobenpunkten, um falsch-positive und falsch-negative Ergebnisse mit einem hohen Maß an Zuverlässigkeit zu vermeiden.
Über die Art des Umwandlungs- / Beschränkungsalgorithmus:
Gegeben: Methode zur Erzeugung eines Pseudozufallswerts p mit 0 <= p <= M
Need: Ausgabe y im (möglicherweise diskontinuierlichen) Bereich 0 <= y <= N <= M
Algorithmus:
r = floor(M / N)
also die Anzahl der vollständigen Ausgabebereiche, die in den Eingabebereich passen.p_max = r * N
p_max
gefunden wirdy = p / r
Der Schlüssel besteht darin, nicht akzeptable Werte zu verwerfen, anstatt sie ungleichmäßig zu falten.
im Pseudocode:
quelle
Abgesehen von der Überprüfung, dass Ihr Code nicht fehlschlägt oder an den richtigen Stellen richtige Ausnahmen auslöst, können Sie gültige Eingabe- / Antwortpaare erstellen (auch manuell berechnen), die Eingabe in den Test einspeisen und sicherstellen, dass die erwartete Antwort zurückgegeben wird. Nicht großartig, aber das ist so ziemlich alles, was Sie tun können, imho. In Ihrem Fall ist dies jedoch kein Zufall. Sobald Sie Ihren Zeitplan erstellt haben, können Sie die Regelkonformität testen. Sie müssen 3 Inspektionen pro Woche zwischen 9 und 9 durchführen. Es gibt keine wirkliche Notwendigkeit oder Fähigkeit, nach genauen Zeitpunkten zu suchen, zu denen die Inspektion stattgefunden hat.
quelle
Es gibt wirklich keinen besseren Weg, als ein paar Mal damit zu arbeiten und zu sehen, ob Sie die Distribution erhalten, die Sie wollen. Wenn Sie 50 mögliche Inspektionspläne zugelassen haben, führen Sie den Test 500 Mal durch und stellen Sie sicher, dass jeder Plan fast 10 Mal verwendet wird. Sie können Ihre Zufallsgenerator-Seeds steuern, um sie deterministischer zu machen. Dadurch werden Ihre Tests jedoch auch enger an die Implementierungsdetails gekoppelt.
quelle
Es ist nicht möglich, eine nebulöse Bedingung zu testen, für die keine konkrete Definition vorliegt. Wenn die generierten Daten alle Tests bestehen, funktioniert Ihre Anwendung theoretisch ordnungsgemäß. Der Computer kann Ihnen nicht sagen, ob die Daten "zufällig genug" sind, da er die Kriterien für einen solchen Test nicht anerkennen kann. Wenn alle Tests bestanden wurden, das Verhalten der Anwendung jedoch immer noch nicht geeignet ist, ist Ihre Testabdeckung empirisch unzureichend (aus TDD-Sicht).
Meiner Ansicht nach ist es am besten, einige willkürliche Einschränkungen für die Datumsgenerierung zu implementieren, damit die Verteilung einen menschlichen Geruchstest besteht.
quelle
Zeichnen Sie einfach die Ausgabe Ihres Zufallsgenerators auf (egal ob Pseudo- oder Quanten- / Chaos- oder reale Welt). Speichern und wiederholen Sie dann die "zufälligen" Sequenzen, die Ihren Testanforderungen entsprechen oder die potenzielle Probleme und Fehler aufdecken, während Sie Ihre Komponententestfälle erstellen.
quelle
Dieser Fall scheint ideal für das eigenschaftsbasierte Testen zu sein .
Kurz gesagt, es ist ein Testmodus, bei dem das Testframework Eingaben für den zu testenden Code generiert und Testzusagen die Eigenschaften der Ausgaben validieren . Das Framework kann dann intelligent genug sein, um den getesteten Code "anzugreifen" und zu versuchen, ihn in einen Fehler zu verwandeln. Das Framework ist normalerweise auch intelligent genug, um Ihren Startwert für den Zufallszahlengenerator zu entführen. In der Regel können Sie das Framework so konfigurieren, dass höchstens N Testfälle generiert oder höchstens N Sekunden ausgeführt werden. Außerdem können Sie fehlgeschlagene Testfälle aus der letzten Ausführung speichern und diese zuerst gegen eine neuere Codeversion erneut ausführen. Dies ermöglicht einen schnellen Iterationszyklus während der Entwicklung und ein langsames, umfassendes Testen außerhalb des Bandes / in CI.
Hier ist ein (dummes, fehlgeschlagenes) Beispiel zum Testen der
sum
Funktion:sum
wird aufgerufen und Eigenschaften des Ergebnisses werden validiertDieser Test findet eine Reihe von "Bugs" in
sum
(Kommentar, wenn Sie in der Lage waren, all diese selbst zu erraten ):sum([]) is 0
(int, kein float)sum([-0.9])
ist negativsum([0.0])
ist nicht streng positivsum([..., nan]) is nan
das ist nicht positivhpythesis
Bricht den Test mit den Standardeinstellungen ab, nachdem 1 "schlechte" Eingabe gefunden wurde, was für TDD gut ist. Ich dachte, es wäre möglich, es so zu konfigurieren, dass es viele / alle "schlechten" Eingaben meldet, aber ich kann diese Optionen jetzt nicht finden.Im OP-Fall sind die validierten Eigenschaften komplexer: Inspektionsart A vorhanden, Inspektionsart A dreimal pro Woche, Inspektionszeit B immer um 12 Uhr, Inspektionsart C von 9 bis 9, [vorgegebener Zeitplan für eine Woche] Inspektionsarten A, B, C alle anwesend usw.
Die bekannteste Bibliothek ist QuickCheck für Haskell. Eine Liste solcher Bibliotheken in anderen Sprachen finden Sie auf der folgenden Wikipedia-Seite:
https://en.wikipedia.org/wiki/QuickCheck
Hypothese (für Python) hat eine gute Zusammenfassung über diese Art von Tests:
https://hypothesis.works/articles/what-is-property-based-testing/
quelle
Was Sie testen können ist, dass die Logik feststellt, ob die zufälligen Daten gültig sind oder ob ein anderes zufälliges Datum ausgewählt werden muss.
Es gibt keine Möglichkeit, einen Generator für zufällige Daten zu testen, ohne eine Reihe von Daten zu erhalten und zu entscheiden, ob sie geeignet zufällig sind.
quelle
Ihr Ziel ist es nicht, Komponententests zu schreiben und diese zu bestehen, sondern sicherzustellen, dass Ihr Programm den Anforderungen entspricht. Sie können dies nur tun, indem Sie Ihre Anforderungen genau definieren. Zum Beispiel haben Sie "drei wöchentliche Inspektionen zu zufälligen Zeiten" erwähnt. Ich würde sagen, die Anforderungen sind: (a) 3 Inspektionen (nicht 2 oder 4), (b) zu Zeiten, die von Personen, die nicht unerwartet inspiziert werden möchten, nicht vorhersehbar sind, und (c) nicht zu nahe beieinander - Zwei Inspektionen im Abstand von fünf Minuten sind wahrscheinlich sinnlos, vielleicht auch nicht zu weit voneinander entfernt.
Sie schreiben die Anforderungen also genauer auf als ich. (a) und (c) sind einfach. Für (b) könnten Sie einen Code schreiben, der so clever wie möglich ist und versucht, die nächste Inspektion vorherzusagen, und um den Komponententest zu bestehen, darf dieser Code nicht besser als reine Vermutungen vorhersagen können.
Und natürlich müssen Sie sich bewusst sein , dass , wenn Ihre Kontrollen wirklich zufällig sind, jeder Vorhersage - Algorithmus könnte rein zufällig richtig sein, so dass Sie sicher sein , dass Sie und Ihre Unit - Tests nicht in Panik geraten , wenn das passiert. Vielleicht noch ein paar Tests durchführen. Ich würde mich nicht darum kümmern, den Zufallszahlengenerator zu testen, denn am Ende zählt der Inspektionsplan, und es spielt keine Rolle, wie er erstellt wurde.
quelle