2016-01-07 2 views
6

Ich bin ein n00b zum Komponententest. Ich habe FsCheck.Nunit und NUnitTestAdapter von Nuget installiert, und ich versuche, Eigenschafts-basierte Tests zu machen, weitgehend inspiriert von the inestimable Scott Wlaschin.Wie kann ich einen eigenschaftsbasierten Test erneut versuchen, wenn die zufallsgenerierten Eingaben nicht sinnvoll sind?

Ich bin mit dem [<Property>] Attribut, und ich würde die Fähigkeit, „überspringen“ Eingänge wie die den Test nicht die Anforderungen erfüllen:

[<Property(MaxTest=10)>] 
let ``Calling unzipTo with an invalid destination will yield a failure.`` badDest = 
    if Directory.Exists(badDest) 
    then // somehow skip to the next randomized input 
    else // do the actual test 

Was ist der einfachste Weg, dies zu tun?

Ich würde eine Antwort für FsCheck/NUnit bevorzugen, wenn es existiert, aber ich würde auch jedes andere Framework betrachten, deren Tests in Visual Studio ausgeführt werden können. (Ich dachte, ich sah ein Framework, wo es eine einfache Funktion gab, um genau das zu tun, aber ich kann nicht herausfinden, was es war.)

Ich habe FsCheck.NUnit bisher bevorzugt, weil es zufällige Eingaben für F # generieren kann Typen (diskriminierte Gewerkschaften usw.) ohne zusätzliche Arbeit.

+0

Sie benötigen einen benutzerdefinierten Generator. –

+0

IIRC für die then-Anweisung müssen Sie nur das Ergebnis zurückgeben, das besagt, dass der Test erfolgreich war, ohne den Test auszuführen. Etwas so Einfaches wie "Wahr" könnte funktionieren.Ich bin in diese Jahre zurückgelaufen und das Problem war das Problem zu überdenken. Denken Sie daran, dass der Test nur eine Funktion ist und der Testfahrer nur ein Ergebnis haben will, das auf Erfolg oder Misserfolg hinweist, also geben Sie ihm einen Erfolg. –

+0

@Guy Coder Der Unterschied ist, dass ich möchte, dass der Test mit verschiedenen Zufallseingaben erneut ausgeführt wird, wenn die generierten nicht nützlich sind - ich möchte nicht, dass die Funktion viele Male mit ungeeigneten Eingaben abläuft und sich selbst als Erfolg deklariert es hat seinen Test nie wirklich durchgeführt. –

Antwort

6

sollten Sie in der Lage sein, so etwas zu tun:

open FsCheck 
open FsCheck.Xunit 

[<Property(MaxTest=10)>] 
let ``Calling unzipTo with an invalid destination will yield a failure.`` badDest = 
    (not Directory.Exists(badDest)) ==> lazy 
    // do the actual test 

Die erste Zeile ist ein boolean Zustand und ==> ist ein benutzerdefinierter Operator durch das FsCheck Modul definiert. Es wird nur die Auswertung des trägen Ausdrucks erzwungen, wenn die Bedingung auf der rechten Seite true ergibt.

Denken Sie jedoch daran, diesen Test zu refactorieren, damit er nicht vom Dateisystem abhängt. Das Dateisystem ist persistent, sodass automatisch eine persistente Vorrichtung erstellt wird, die a lot of trouble to manage ist; nicht unmöglich zu bewältigen, aber besser vermieden werden.

Dieses Beispiel verwendet FsCheck.Xunit, aber IIRC FsCheck.Nunit die gleiche Art und Weise funktioniert. Sie sollten ernsthaft in Betracht ziehen, FsCheck.Xunit statt FsCheck.Nunit zu verwenden. Das Erweiterbarkeitsmodell von NUnit 2 ist außergewöhnlich schlecht, was bedeutet, dass die meisten Glue Libraries, die versuchen, NUnit zu erweitern, mit vielen Problemen konfrontiert sind. Dies ist kein Problem mit FsCheck.Nunit, aber mit NUnit selbst, aber es wird sich in vielen Schwierigkeiten für Sie manifestieren.

+0

Großartig, genau das habe ich gesucht. Ich habe es wahrscheinlich zuerst auf deinem Blog gesehen. Danke für den Tipp auf NUnit vs Xunit. –

+0

Normalerweise versuche ich, Tests unabhängig vom Dateisystem, DB-Status usw. zu halten, aber für die Funktionen, die ich hier entwickle, ist die Manipulation des Dateisystems ihr Hauptzweck. Wie sonst kann ich sie überhaupt testen? –

+0

@OverlordZurg Vielleicht beantwortet diese Antwort diese Frage: http://codereview.stackexchange.com/a/99290/3878 ... oder vielleicht nicht :) –

0

Ich bin nicht sehr vertraut mit F # oder fscheck, aber NUnit bietet die Assert.Ignore()-Funktion, die sofort den Test stoppt und es als "ignoriert" markiert. Sie könnten auch Assert.Inconclusive() oder Assert.Pass() verwenden, wenn Sie der Meinung sind, dass diese Status geeigneter sind.

+0

Ich habe versucht "Assert.Ignore()", aber das verursacht Tests mit dem Attribut [] markiert fehlschlagen, das ist nicht das Verhalten, das ich will. –

1

FsCheck.Prop.discard() scheint zu tun, was ich will - wenn ich den Test mit der Protokollierung ausführen, kann ich sehen, dass einige Versuche verworfen wurden, aber 10 Läufe wurden abgeschlossen, ohne verworfen zu werden.

Der Operator ==> arbeitet für die Tests mit FsCheck.Quick oder ähnlichem. Dies erfordert jedoch, dass der faule Teil im Format "Testable" ist, wobei die Tests, die ich gerade schreibe, nur <inputs>->unit sind.

+1

* "das erfordert, dass der faule Teil im Format von "Testbar" * Das sollte kein Problem sein. Der Compiler wird den passenden Typ für Sie ableiten. Beispiele finden Sie hier: http://blog.ploeh.dk/2015/09/08/ad-hoc-arbitraries-with-fscheckxunit –

+2

Aufruf von 'discard' in Ihrem 'then'-Zweig oder Verwendung des Ansatzes mit' == > 'sollte völlig gleichwertig sein. Obwohl '==>' ist der bevorzugte Ansatz - es liest besser imo und "discard" funktioniert durch Werfen und Abfangen einer Ausnahme unter der Haube, so kann langsam und störend für das Debuggen sein. –

+0

Ich habe das Problem gefunden - Ich habe versucht, die Einheit zurückzugeben, aber ich musste Bool zurückgeben. Leider bringt mich das Zurückgeben von Bool aus dem Lazy-Teil (statt Assert.AreEqual()) zu der netten Formatierung, die explizit den erwarteten und den tatsächlichen Wert angibt. Ich werde weiterhin Optionen erkunden, aber zumindest verstehe ich jetzt :) –

Verwandte Themen