2013-12-16 4 views
32

Wann sollte debug.assert über Code-Verträge oder umgekehrt? Ich möchte die Vorbedingung für eine Methode überprüfen und bin verwirrt, um eine über die andere zu wählen. Ich habe Komponententests, bei denen ich Fehlerszenarien testen und Ausnahmen erwarten kann.Debug.Assert vs Code Vertragsverwendung

Ist es eine gute Praxis, Debug.Assert und Code-Vertrag auf der gleichen Methode zu verwenden. Wenn ja, in welcher Reihenfolge sollte der Code geschrieben werden?

Debug.Assert(parameter!= null); 
Contract.Requires<ArgumentNullException>(parameter != null, "parameter"); 

oder

Contract.Requires<ArgumentNullException>(parameter != null, "parameter"); 
Debug.Assert(parameter!= null); 

Gibt es eine Logik dahinter?

Antwort

28

Dies sind verschiedene Dinge. Eine Debug-Assertion wird nur ausgeführt, wenn der Code als Debug kompiliert wird und daher nur unter Debug debuggt. Die Idee ist, dies für "Health Checks" für den Code, den Sie entwickeln, zu verwenden. Code-Verträge können entweder in debug oder release verwendet werden. Sie stellen sicher, dass die Vor- und Nachbedingungen der Methoden den Erwartungen der Methode entsprechen (Vertrag erfüllen). Es gibt auch ein Test-Framework, das ähnliche Funktionen zur Überprüfung der Test-Compliance bietet.

Verwenden Sie Debug.Assert, wenn Sie sicherstellen möchten, dass bestimmte Dinge so sind, wie Sie es erwarten, wenn Sie den Code entwickeln (und in der späteren Wartungsentwicklung).

Verwenden Sie Code-Verträge, wenn Sie sicherstellen möchten, dass die Bedingungen in Debug und Release erfüllt sind. Verträge erlauben auch bestimmte Formen der statischen Analyse, die hilfreich sein können, um zu überprüfen, ob Ihr Programm "korrekt" ist.

Verwenden Sie die Test-Framework-Assertions beim Erstellen von Komponententests.

+0

stimme ich voll und ganz zu, aber wenn ich wählen, debug.assert und Code-Vertrag an der gleichen Stelle sollte es in einer bestimmten Reihenfolge sein? – CarbineCoder

+0

Nicht sicher, warum Sie auf diese Weise eine doppelte Überprüfung durchführen würden. Ordnung sollte nicht herrschen. Wenn ich das täte, glaube ich, dass ich den Debug.Assert zuerst als eine Entwicklungsdebugginghilfe setzen würde. – Dweeberly

+0

Debug.Assert wird nicht in Release-Code vorhanden sein, aber Code-Verträge werden. Ich denke, es gibt Fälle, in denen debug.assert parallel zu Code-Verträgen benötigt wird - ich könnte mich irren. Daher die Frage. – CarbineCoder

22

Persönlich würde ich beide nicht Debug.Assert und Code verwenden Contracts Voraussetzungen in neu geschriebenen Code zu erzwingen - IMO-Code Contracts supercede Debug.Assert, da sie eine umfassende Suite von Schecks zur Verfügung stellen, nicht den Vorteil zu nennen, die aus gewonnen werden können Die statische Überprüfung, die durchgeführt werden kann bevor der Code zur Laufzeit. Das Aufrechterhalten doppelter Vorbedingungsprüfungen sowohl in Debug.Assert als auch in Contracts wird umständlich sein.

Begründung:

  • Sie brauchen keine Legacy-Voraussetzungen erneut Code, den Sie in Debug.Assert oder throw Code codiert haben - die vorhandene Voraussetzung Prüfcodes halten und terminate it with Contract.EndContractBlock()
  • Sie kann das gleiche ungeprüfte "Freigabemodus" Verhalten erhalten, wenn System.Diagnostics.Debug ohne /d:DEBUG gebaut wird, wenn Sie mit Kontraktlaufzeitprüfung auf None gesetzt bauen.
  • Contracts ermöglicht es einem Entwickler, im Code ausdrucksstarker zu sein, warum "ein ungültiger Zustand erkannt wurde - z. war es direkt wegen eines Out-of-Band-Parameters (Contract.Requires). Ansonsten kann Contract.Assert oder Contract.Assume den allgemeinen Zustand prüfen, und die "garantierte Korrektheit" des Zustands beim Verlassen einer Methode kann mit Contract.Ensures ausgedrückt werden. Und Invariants zum Ausdruck bringen, dass der Staat immer gehalten werden muss.
  • Und das Beste von allem, Statische Überprüfung kann diese Verträge erzwingen, wie Sie Ihren Code erstellen - auf diese Weise haben Sie die Chance, den Fehler durch eine Entwurfszeit oder Kompilierzeit Warnung abzuholen, anstatt auf Laufzeit warten müssen.Vertragsprüfungen können Ihrer Continuous Integration hinzugefügt werden, um nach Nichteinhaltung zu suchen.

Eine Warnung: Wenn Sie Unit-Tests schreiben, werden die Verträge absichtlich verletzen, können Sie mit ContractException befassen müssen - Jon Skeet erklärt diese gut here. z.B. Verbinden Sie einen Contract.ContractFailed handler in Ihrem Test-Setup mit einem Handler, der SetHandled aufruft und dann eine öffentliche Exception auslöst, die Sie in Ihren UTs abfangen und bestätigen können.

+2

Schöne Erklärung. Jetzt habe ich es verstanden. Wenn es konsistent verwendet wird, bringt es so viel Klarheit darüber, was der Entwickler auf dem ganzen Weg über den Zustand der Anwendung annimmt. Und das ist nur Sahnehäubchen auf dem Kuchen, der Kuchen ist ausführlicher und komplette Ausnahmehandhabungsroutinen, die von Anfang an leicht zu setzen sind. – jeremcc

+0

Nur wenn es eine lösungsweite Konfigurationseinstellung gab, um sicherzustellen, dass 'Contract.Assert's nicht in Release Build enden, würde ich sie verwenden. Ansonsten benutze ich 'Debug.Assert', weil ich weiß, dass sie niemals in Release-Build eindringen werden. Konfiguration Wartung von Code-Verträgen ist der größte Nachteil IMO. – orad

+0

Hinzufügen zu meinem vorherigen Kommentar, für Vorbedingungen und Post-Bedingungen auf öffentlichen Schnittstellen Ich sehe, warum wir sie in Release-Modus für die Verwendung des Consumer-Code einschließen möchten. Aber ich sehe keinen Grund, warum wir in jedem Fall Behauptungen in den Freigabemodus aufnehmen wollen. Ich bin vielleicht nicht genug darüber informiert. – orad