Code verhält sich in Release vs. Debug-Modus anders

8

Wir haben einige Komponententests, die fehlschlagen, wenn sie im Freigabemodus oder im Debug-Modus ausgeführt werden. Wenn ich einen Debugger im Freigabemodus anschließe, werden die Tests bestanden. Es gibt viel zu viel Code, um hier zu veröffentlichen, also suche ich wirklich nur nach Best Practices beim Debuggen von Release-Modus-Problemen. Ich habe nach:

gesucht

LÖSUNG: In diesem Fall ist es, weil ich Fließkommavariablen für Gleichheit vergleiche. Ich konnte die Gleitkommawerte nicht ohne großen Refactoring in Dezimalzahlen ändern, also fügte ich eine Erweiterungsmethode hinzu:

%Vor%     
Shaun Bowe 24.01.2011, 20:57
quelle

6 Antworten

3

Da es scheinbar fließend ist, gibt es so viele Dinge, die schief gehen können. Sehen: C # - Inkonsistente mathematische Operation führt zu 32-Bit und 64-Bit und Probleme mit doppelter Genauigkeit unter .NET

Es gibt so viele Dinge, die mit Fließkommazahlen verworfen werden können. Und das Vergleichen von Schwimmern für die Gleichheit ist ein generelles Nein-Nein. Sie können den Unterschied kleiner als ein vernünftiges Epsilon überprüfen.

    
stefan 24.01.2011, 21:10
quelle
8

Eine Sache, die das angezeigte Verhalten verursachen könnte, ist ein Fehler, der eine Wettlaufbedingung verursacht. Durch das Hinzufügen eines Debuggers kann das Timing des Codes so geändert werden, dass die Race-Bedingung nicht mehr ausgelöst wird.

Um es zu beheben, verwenden Sie die Synchronisierung immer dann, wenn mehrere Threads auf Daten zugreifen.

  

Ich vergleiche einige Float-Werte in der IsEqual-Methode.

Das klingt nach einer sehr schlechten Idee. Sie sollten Floats nicht mit Gleichheit vergleichen, da Fließkomma-Berechnungen nicht zu 100% präzise sind und Sie Repräsentations- und Rundungsfehler erhalten können. Vergleichen Sie, um festzustellen, ob sie ausreichend nahe beieinander liegen. Bei Berechnungen mit Geld möchten Sie wahrscheinlich stattdessen den decimal -Typ verwenden.

    
Mark Byers 24.01.2011 21:01
quelle
2

Fragen, die Sie sich stellen sollten -

  1. Ist mein Code eingefädelt? Timing-Unterschiede beeinflussen die Ausgabe
  2. Ruft jemand Debug.Assert () mit einem Ausdruck, der Nebenwirkungen hat?
  3. Welche Objekte implementieren IDisposable () und tun einige so, dass sich der Zustand ändert?
  4. Sind Sie in nicht verwaltetem Code aktiv?

Nummer 3 ist in diesem Fall ein sehr wahrscheinlicher Bad Boy. Die Garbage-Collection kann beim Debuggen und Freigeben sehr unterschiedlich sein. Wenn ein Garbage Collection-Objekt erfasst wird, wirkt sich dies möglicherweise auf das Ergebnis eines späteren Unit-Tests aus.

Und zu guter Letzt, wenn Sie NUnit und TestDriven.NET verwenden - die beiden führen Tests in verschiedenen Ordnungen durch

    
plinth 24.01.2011 21:09
quelle
2

Dies ist oft der Fall, da das Debug-Build standardmäßig nicht optimiert ist. Selbst wenn Sie es aktivieren, ist das Verhalten beim Debugging sehr unterschiedlich. Sie können den "Code optimieren" in den Projekteinstellungen für alle Assemblys auf der Registerkarte Eigenschaften- & gt; Erstellen deaktivieren.

Es gibt sicherlich noch andere Änderungen, die zu Unterschieden führen können. Diese habe ich selten als Ursache von Problemen gefunden, für mich ist es fast immer der Optimierer.

Klassische Fehler des Optimierers schließen Methoden ein, die "inline" erhalten, so dass sie nicht auf einem Call-Stack erscheinen. Dies führt zu Problemen bei der Verwendung von System.Diagnostics.StackFrame-Klassen zum Ermitteln des aktuellen Ausführungspunkts. In ähnlicher Weise beeinflusst dies das Ergebnis von MethodBase.GetCurrentMethod oder anderen Funktionen / Verhalten, die auf der ausführenden Methode beruhen.

Dann gibt es natürlich viele Dinge, die ich vom Optimierer gesehen habe, die ich einfach nicht erklären kann. Ein solches Beispiel wurde dokumentiert und diskutiert in einem Post ' HashDerivedBytes - ersetzt Rfc2898DeriveBytes, aber warum? ' aber ich habe das nie gelöst Geheimnis. Ich weiß nur, dass der Optimierer Rfc2898DeriveBytes nur flach brach, wenn er verwendet wurde, um eine Reihe von abgeleiteten Bytes zu erzeugen. Seltsamerweise brach dies nur, wenn die erzeugten Bytes nicht gleichmäßig durch die Größe des verwendeten Hash-Algorithmus teilbar waren (20) und nur falsche Ergebnisse nach den ersten 20 Bytes erzeugten.

Fakt ist, dass Optimierungen, die den Code beeinträchtigen, für Compiler keine neue Sache sind. Die meisten C ++ - Entwickler der alten Schule werden dir das sofort erzählen und dann, wie ich es getan habe, in eine langatmige Geschichte darüber gehen, wie sie damit umgehen;)

    
csharptest.net 24.01.2011 21:42
quelle
0

Wie Mark vermutet, ist dies in der Regel auf ein Timing-Problem zurückzuführen, oft auf ein Race Condition- oder Synchronisationsproblem.

Ein gängiger Weg, um diese Art von Problem zu lösen, ist die Verwendung von "print" -Anweisungen in den betroffenen Bereichen, um Ihnen zu zeigen, was vor sich geht. Wenn die print-Anweisungen ( Console.WriteLine , Response.Write , Protokollierung oder was auch immer) das Problem verschwinden lassen, speichern Sie die Werte in globalen Variablen und drucken Sie die Globals, sobald das Problem auftaucht.

Die letzte Zeit, die mir passiert ist, war Code, der von einer seriellen Schnittstelle gelesen hat. Die Debugging-Aktivität führte gerade zu einer Änderung des Timings, die sich auf die Pufferung der Bytes aus dem seriellen Port auswirkte. Dadurch wurde die Analyse des Puffers geändert. Da die Druckanweisungen das Timing änderten, musste ich die Daten bis zur Ausgabe speichern.

    
Gabe 24.01.2011 21:05
quelle
0

Um nur meine zwei Cent dazu hinzuzufügen, habe ich kürzlich festgestellt, dass ich einen Datumsvergleich in einer SQL-Prozedur hatte, die der Test aufgerufen hat. Die Daten wurden alle zuvor in der Testprozedur automatisch generiert, und Werte wurden in die Datenbank eingefügt. Daher waren sie gelegentlich genau gleich (wenn RunTests verwendet wurden), wodurch bei einem Tabellenjoin eine Null zurückgegeben wurde. Nicht was ich erwartet hatte. Offensichtlich wird es im Debug-Modus einen Unterschied in den automatisch generierten Zeiten geben, was bedeutet, dass ich nie auf den Fehler stieß. Ich habe das gelöst, indem ich

eingefügt habe

Threading.Thread.Sleep (520)

wo immer es eine Verzögerung zwischen den Aktionen geben würde. Problem gelöst.

    
user676767 25.10.2011 11:14
quelle

Tags und Links