Debuggen, Fehler finden und beseitigen

    • VB.NET

    Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

      Debuggen, Fehler finden und beseitigen

      Irgendwie habe ich das Gefühl, dass unsere Kollegen Jungprogrammierer der Meinung sind, sie schreiben irgend einen Code und der funktioniert dann auch genau so, wie sie es sich gedacht haben. Und wenn dem nicht so ist (also fast immer), wird im Forum ein Thread aufgemacht.
      Genau so denke ich, dass die (Un-)Kollegen Lehrer ihren Schülern genau dies beibringen, weil sie selber nicht über die erforderlichen Kenntnisse und Erfahrungen verfügen.
      Deswegen möchte ich hier mal ein paar Worte zur erfolgreichen Programmentwicklung schreiben.
      Das Programmbeispiel hane ich aus diesem Thread von @faxe1008: genommen, den Pfad der Ausgabedatei habe ich in das Verzeichnis "C:\Temp\" verlegt, der Rest des Programms ist hier nicht von Belang.
      Ich unterstelle mal dem Programm, dass eine MessageBox kommen soll, wenn das Programm up to date ist.
      Beispielcode

      VB.NET-Quellcode

      1. Imports System.IO
      2. Public Class Form1
      3. Dim updated As Boolean
      4. Dim lastupdate As DateTime
      5. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      6. Dim str As New FileStream("C:\Temp\lastupdate.txt", FileMode.Open)
      7. Dim reader As New StreamReader(str)
      8. Dim laststring As String = reader.ReadLine
      9. lastupdate = CDate(laststring)
      10. str.Close()
      11. If lastupdate.AddDays(7).Date = DateTime.Now.Date Then
      12. updated = True
      13. MsgBox("funkt")
      14. End If
      15. End Sub
      16. End Class
      Beim Start mit F5 passiert nix, keine MessageBox, klar, die Woche ist noch nicht vorbei.
      Aber testen wollen wir die Funktionalität doch.
      Und Wie?
      OK, kleiner Trick, wir testen nicht den Ablauf einer Woche, wir ersetzen die Testbedingung durch True, da ist sie stets erfüllt:

      VB.NET-Quellcode

      1. If True Then 'If lastupdate.AddDays(7).Date = DateTime.Now.Date Then
      Allerdings müssen wir das nach dem Test wieder rückgängig machen.
      Beim Start mit F5 passiert nix, keine MessageBox. :S
      Oft genug wird in die Form_Load ein Code reingeschrieben, und das Programm bricht nach einer Exception die Abarbeitung dieser Form_Load ab, meldet aber diese Exception nicht :!:
      Zunächst muss jedem Programmierer klar sein, dass er jede einzelne geschriebene Programmzeile auch testen muss! Und das funktioniert nicht einfach mit F5 und fertig, sondern man muss sich davon überzeugen, dass das Programm auch an dieser Zeile vorbei gekommen ist.
      Das Studio ist ein mächtiges Entwicklungswerkzeug mit vielen Funktionen, die uns das Fehlerfinden erleichtern.
      Der Haltepunkt: Mit F9 kann man im Code einen Haltepunkt festlegen, wo dann beim Debug-Lauf ein Break durchgeführt wird.
      Haltepunkt auf die 1. ausführbare Zeile der Form_Load und dann Schritt für Schritt ausgeführt bis entweder die Prozedur ordnungsgemäß beendet oder bis bei einer Exception die Prozedur verlassen wurde.

      In unserem Beispiel wird die Form_Load bereits in Zeile 6 beendet.
      Jou. Hilfe oder Thread im Forum oder mal nachsehen, was in C:\Temp steht - gefunden.
      Eine nicht vorhandene Datei kann ich nicht mit FileMode.Open öffnen. Also:

      VB.NET-Quellcode

      1. Dim str As New FileStream("C:\Temp\lastupdate.txt", FileMode.OpenOrCreate)
      Haltepunkt weg und wieder F5 - nix, keine MessageBox. :S
      Also wieder einen Haltepunkt auf diese Zeile. Diesmal stept er weiter bis zur Zeile 10.
      Da setzen wir nun den nächsten Haltepunkt hin.

      Mit der Maus über der Variable laststring wird uns deren Wert angezeigt. Klicken wir auf die Reißzwecke, wird diese Anzeige fixiert.

      Klar. Ein Leerstring lässt sich nicht in ein DateTime konvertieren.
      MSDN, Forum, Erleuchtung:

      VB.NET-Quellcode

      1. Dim result = DateTime.TryParse(laststring, lastupdate)
      Nun kommt beimm Start mit F5 die lang ersehnte MessageBox.
      Nun müssen wir die If True-Bedingung wieder zurückeditieren.
      Dabei fällt uns auf:
      Nur, wenn das Datum genau vor einer Woche war, kommt die MessageBox. Hier müssen wir nun überlegen, was wir eigentlich wollen.
      1. Wenn die Datei nicht vorhanden ist, ist das Programm neu oder nicht (Philosophie-Frage, wurde ein altes Programm kopiert)? Dies soll hier nicht von Belang sein.
      2. Wenn ich 2 Wochen krank oder in Urlaub war, bekomme ich keine Meldung.
      Es ist also notwendig, nicht auf einen Zeitpunkt, sondern auf einen Zeitraum zu testen.
      Das Programm ist also up to date, wenn der Eintrag jünger als eine Woche ist. Das müssen wir nun programmieren:

      VB.NET-Quellcode

      1. If lastupdate.AddDays(7).Date >= DateTime.Now.Date Then

      Um dies zu testen, öffnen wir die Datei mit dem Notepad und schreiben mal ein jüngeres und mal ein älteres Datum rein, um uns davon zu überzeugen, dass die Logik funktioniert.
      OK.
      Nun kann das nächste Problem in Angriff genommen werden.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Ergänzend noch die Bemerkung, dass der Umstand, dass im Form_Load ein Fehler auftritt, der nicht zum Programmabbruch und Anlaufen des Debuggers führt, vor allem eine gravierende Fehlfunktion des VisualStudio auf Betriebssystemen ab Windows Vista ist.

      Für Debug-Zwecke ist es oft möglich, den Startup-Code aus dem Form_load herauszunehmen, und einfach ins Form_Shown - Event zu verlegen
      minimal geänderter BeispielCode

      VB.NET-Quellcode

      1. Imports System.IO
      2. Public Class Form1
      3. Dim updated As Boolean
      4. Dim lastupdate As DateTime
      5. Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Shown 'MyBase.Load
      6. Dim str As New FileStream("C:\Temp\lastupdate.txt", FileMode.Open)
      7. Dim reader As New StreamReader(str)
      8. Dim laststring As String = reader.ReadLine
      9. lastupdate = CDate(laststring)
      10. str.Close()
      11. If lastupdate.AddDays(7).Date = DateTime.Now.Date Then
      12. updated = True
      13. MsgBox("funkt")
      14. End If
      15. End Sub
      16. End Class
      Seit ewigen Zeiten (jedenfalls noch von vor VB6) konnte man sich als Programmierer drauf verlassen, dass Laufzeitfehler beim Testen zum Programm-Abbruch und Anlaufen des Debuggers führten.
      Logischerweise werden nun viele Programmierer z.T. plan- hilf- und endlos nach Gründen von Fehl-Funktionalität suchen, weil da kommt man ja nur sehr langsam drauf, dass nunmehr und in diesem Event (Form_Load) eine Exception sich nicht mehr per Debugger zu Wort meldet :( .

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Das Thema liegt schon eine Weile zurück, aber ich finde, dass es immer noch aktuell ist. Außerdem ist es im Tipps & Trick und Tutorial - Bereich.

      Was spricht dafür, das Load-Ereignis zu verwenden?
      Mir ist bisher noch nichts untergekommen, was man nicht auch in den Konstruktor (oder in den Shown-EventHandler) packen könnte.
      "Luckily luh... luckily it wasn't poi-"
      -- Brady in Wonderland, 23. Februar 2015, 1:56
      Desktop Pinner | ApplicationSettings | OnUtils

      Niko Ortner schrieb:

      Was spricht dafür, das Load-Ereignis zu verwenden?
      Meintest Du ggf. "nicht zu verwenden"?
      Es gibt innerhalb Form_Load (mindestens) 2 Sorten von Exceptions:
      Diejenigen, die "ignoriert" werden, aber zum vorzeitigen Abbruch der Form_Load-Prozedur führen
      und
      "ganz normale" Exceptions, die eine ordentliche Meldung bringen.
      Für Anfänger ist es meist sehr schwer, der 1. Sorte auf die Spur zu kommen.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      @RodFromGermany:
      Ja, ich meinte damit, dass man es meiden sollte. Also wenn man es nicht braucht. Und dazu eben die Frage, warum man es denn überhaupt braucht.
      Wie gesagt, ich hatte bisher noch nichts, was man nicht auch in den Konstruktor verlegen hätte können (oder in einen Shown-EventHandler).
      "Luckily luh... luckily it wasn't poi-"
      -- Brady in Wonderland, 23. Februar 2015, 1:56
      Desktop Pinner | ApplicationSettings | OnUtils

      Niko Ortner schrieb:

      ich hatte bisher noch nichts, was man nicht auch in den Konstruktor verlegen hätte können
      Wenn Du UserControls baust, die Du in der GUI einsetzt, sollte der Code, der die UserControls nicht im Designer parametrisiert, nicht im Konstruktor stehen, und da wird üblicherweise (Doppelklick auf die GUI) die Form_Load verwendet.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      Niko Ortner schrieb:

      ich hatte bisher noch nichts, was man nicht auch in den Konstruktor verlegen hätte können (oder in einen Shown-EventHandler).
      Das ist aber ein wesentlicher Unterschied.
      Exceptions im Konstruktor werden ebenso verschluckt, wie Exceptions im Form_Load.
      Wie gesagt: Das Form_Shown - Event ist der frühestmögliche Zeitpnkt, ab dem Exceptions nicht mehr verschluckt werden.

      ErfinderDesRades schrieb:

      Exceptions im Konstruktor werden ebenso verschluckt


      Ich würde das gerne testen, aber ich habe gerade kein 32-Bit Windows zur Verfügung. Falls das tatsächlich der Fall ist, habe ich das falsch verstanden.
      "Luckily luh... luckily it wasn't poi-"
      -- Brady in Wonderland, 23. Februar 2015, 1:56
      Desktop Pinner | ApplicationSettings | OnUtils