OpenKeyWord  Version: 426, Datum:
Die Behandlung von Ausnahmen

Exception Handling in OKW

In diesem Kapitel wird zunächst beschrieben, wie Ausnahmen im OKW-Kernel behandelt werden. Im Anschluss wird gezeigt, wie Ausnahmen (engl. Exceptions) in GUI-Klassen implementiert werden müssen, damit diese OKW-konform sind und vom Kernel abgearbeitet werden können.

OKW State Entwurfsmuster

Für das Verständnis der Behandlung von Ausnahmen in OKW ist es zunächst wichtig zu wissen, dass der Kernel von OKW als State Pattern implementiert ist.

Zu beachten
Das Thema State-Entwurfsmuster wird hier nicht näher erläutert und auf die Einführung unter http://www.philipphauer.de/study/se/design-pattern/state.php verwiesen.

OKW hat ein sehr einfaches Zustandsmodell und besteht aus folgenden Zuständen bzw. Klassen:

  • CORE ist das so genannte Context-Objekt.
  • Zustand OK: wird durch die Klasse OK representiert. Dieser Zustand bleibt bestehen, so lange kein Ausnahmefall eingetreten ist. In diesem Zustand interagiert das Script mit dem AUT.
  • Zustand NOK: (NOK = Not OK) wird durch die Klasse NOK representiert. Dieser Zustand wird eingenommen,wenn eine Ausnahme ausgelöst wurde.
  • In diesem Zustand interagiert das Script nicht (mehr) mit dem AUT.

Es gibt folgende Zustandsübergänge:

  • Im Ausgangsstatus wird mit dem Zustand OK begonnen.
  • Sollte ein Testfall bereits vorher einen Fehler gefunden haben, dann wird mit NOK.BeginTest() wieder in den Zustand OK gewechselt.
  • Wenn im Zustand OK ein Fehler auftritt, dann wird in den Zustand NOK gewechselt.

OKW Exceptions

In OKW sind folgende Ausnahmen denkbar, die zum Abbruch-Fehler eines Testfalls führen müssen:

  • Kernel-Exception wird vom OKW -Kernel ausgelöst, wenn voraussehbare Probleme im Kernel auftreten.
    Beispiel: Falscher fachlicher Bezeichner eines GUI-Objektes.
    Es wird eine Fehlermeldung mit Hinweis auf den möglichen Fehler ausgegeben. Danach wird die Ausführung des aktuellen Skriptes abgebrochen: Der Kernel wechselt in den Status NOK.
  • GUI Exception wird von OKW GUI-Klassen ausgelöst. Diese Klassen implementieren die Zugriffe auf die Oberflächen über ein Automatisierungswerkzeug.
    Beispiel: Die Objekterkennungseigenschaft ist falsch und das Automatisierungswerkzeug findet daher das GUI-Objekt nicht.
    Hier wird/sollte ein OKW_GUI_Exception ausgelöst.
  • System.NotImplementedException ist in den Methoden der abstrakten Klassen von OKW implementiert, wenn eine Methode noch implementiert werden muss.
  • unerwartete Exceptions werden aus nicht vorhersehbaren Gründe ausgelöst. Für die Analyse dieser Ausnahmebehandlung erfolgt eine Ausgabe der Ausnahme in Tabellenform mit Referenz auf die Methode.
Noch zu erledigen:
Letzten Satz auf Richtigkeit prüfen!!!
Bemerkungen
  • Alle Ausnahmen, die zum Abbruch des Skriptes führen müssen, werden im Zustand OK und nur dort abgefangen und behandelt.
  • All diese Ausnahmen haben zur Folge, dass aus dem Zustand OK in den Zustand NOK gewechselt und damit der aktuell ausgeführte Testfall beendet wird.

Zwei häufig vorkommende Fehler, die immer zu einem Abbruch führen müssen, sind:

  • Durch einen Tippfehler in einem fachlichen Bezeichner $$ des FrameObjekts wird der gegebene Bezeichner als nicht existent eingestuft und kann daher nicht erkannt werden. Hier wird ein OKW_KernelException ausgelöst.
  • locator - Objekt Erkennungseigenschaft ist falsch: Das gesuchte GUI-Objekt wurde nicht erkannt, die angefangene Aktion kann nicht weiter durchgeführt werden. Hier muss ein OKW_GUI_Exception ausgelöst werden. Dieser Fehler entsteht in einer GUI-Klasse.

Grundprinzipien der Ausnahme-Behandlung

catch

  1. Fange niemals eine Ausnahme ab, die Du nicht an Ort und Stelle behandeln kannst.
  2. Eine Ausnahme, die zum Abbruch des Skriptes führen muss, wird ausschließlich vom OKW-Kernel, der Klasse OKW, abgefangen und behandelt.

In OKW kommen prinzipiell zwei Arten von Ausnahmen vor.

  • Erwartete d.h. bekannte Ausnahmen. - Hier wird eine eine Meldung mit Hinweis ausgegeben und der Testfall beendet.
  • Unerwartete Exception- - Hier werden alle Relevanten Informationen geloggt und der Testfall beendet.

Ergebnis von beiden ist, dass der aktuelle Testfall beendet werden muss. -> Wechseln in den NOK-Zustand.

Anwedungsbeispiel

1 private bool CheckCharacter(String fpsFunctionalname )
2 {
3  // Variable
4  Boolean lvb_Return = true;
5 
6  // Initialisierung
7 
8  // Define a regular expression OKW_Object Name.
9  Regex rx = new Regex(@"^-?\d+(\.\d{2})?$");
10 
11  // Check each test string against the regular expression.
12  if (rx.IsMatch(fpsFunctionalname)){
13  lvb_Return = true;
14  }
15  else{
16  String Error_Text = LogMessenger.Instance.GetMessage("CurrentObject", "CheckCharacter", "IllegalCharacters_Exception" );
17  throw new OKW_Kernel_Exception(Error_Text );
18 
19  lvb_Return = false;
20  }
21 
22  return lvb_Return;
23 
24 }

Unittest erwarteter Ausnahmen

Alle erwarteten Ausnahmen müssen mit einem Unittest abgeprüft werden.

Die Auflistung unten zeigt, wie geprüft werden kann, ob die Ausnahme OKW_GUI_Exception wie erwartet ausgelöst wird.

Hierzu sind mehrere Anmerkungen zu machen:

  • Die erwartete Auslösung der Ausnahme wird getestet, indem der Aufruf der Methoden, die die Ausnahme auslösen soll, in einen try...catch Block gekapselt wird.
  • Es wird nur die spezielle Ausnahme OKW_Kernel_Exception abgefangen und Assert.Pass().
  • Alle anderen Ausnahmen werden durch catch (Exception e ) die Testmethode selbst behandelt und führen mit Assert.Fail() zum gewünschten Fehlschlagen des Tests.
  • Wird gar keine Ausnahme ausgelöst, führt die Ausführung der NUnit-Methode wiederum mit Assert.Fail() zum Scheitern des Tests.
1 /// <summary>
2 /// Testziel: Prüfen, ob ein OKW_Kernel_Exception in der Methode CurrentObject.SetChildName() ausgelöst wird.<br/>
3 /// Auslöse-Grund ist, wenn ein Kind-Objekt angesprochen wird, ohne das voher ein Fenster-Objekt ausgewählt worden ist.<br/>
4 /// </summary>
5 /// \remark Folgende Reaktionen sind denkbar:
6 /// 1. OKW_Kernel_Exception wird ausgelöst: KernelException wird true gesetzt.
7 /// 2. Es wird eine anderere beliebige Ausnahme (Exception) ausgelöst: Kernel-Exception wird false gesetzt.
8 /// 3. Es wird keine Ausnahme ausgelöst: im try-Block als letztes ausgeführt.
9 ///
10 /// \~
11 /// \author Zoltan Hrabovszki
12 /// \date 2012.12.16
13 [Test()]
14 public void TC_SetChildName_Exception ()
15 {
16  // Wert, der den mit Assert.True() getestet wird. Initialisierung erfolgt auf false.
17 
18  Logger.Instance.LogFunctionStart ("TC_SetWindowName");
19 
20  try {
21  // Exception wird ausgelöst wenn ein Fenster Objekt nicht gesetzt ist.
22  // Der Namen des Fensters wurde hier daher bewusst weggelasssen
23  // CurrentObject.SetWindowName("Rechner" );
24  CurrentObject.Instance.SetChildName ("Taste_3");
25 
26  // Diese Zeile darf nicht mehr ausgeführt werden, daher fail
27  Assert.Fail();
28 
29  }
30  catch (OKW_Kernel_Exception e)
31  {
32  // Richtige Exception wurde ausgelöst daher Pass!
33  Assert.Pass();
34  }
35  catch (Exception e )
36  {
37  // Alle anderen Exceptions sind Fail!
38  Assert.Fail();
39  }
40  Logger.Instance.LogFunctionEnd();
41 }

Nun werden aber oft Werkzeuge eingesetzt, die prüfen, ob hinterlegte Regeln beim Programmieren eingehalten wurden. Daher steht innerhalb des Catch-Blocks ein einzelnes Semikolon. Es repräsentiert die leere Anweisung (aus Assemblerzeiten etwa als NOP – was für NO Operation steht – bekannt). Fehlt diese leere Anweisung,führt dies bei bekannten Syntaxprüfern wie CheckStyle [4] oder PMD [5] zu einer ungewollten und überflüssigen Warnung. Der knappe Kommentar hinter dem Semikolon erfüllt Dokumentationszwecke und sollte nicht fehlen.

Literatur- und Linkverzeichniss

Beispiel: Wenn jemand ein Kindobjekt bearbeiten oder prüfen will, aber das Elternobjekt -also das Fenster- nicht gewählt hat, dann wird ein OKW_KernelException in der Klasse CurrentObject ausgelöst.

  • An dieser stelle wird geschaut, ob der Fensterbezeichner gesetzt ist.

In der Klasse OKW, also hierarchisch ganz oben) jeweils in den Schlüsselwörtern (z.B. Methode Select()) fange ich "alle" Exception ab. Erzeuge eine entsprechende Meldung (Log):