Feb 3 2010

MVC-Pattern im Web

Das MVC-Pattern gibt es schon seit dem 20. Jahrhundert. Publiziert wurde es in den 90er Jahren zusammen mit dem Buch “Design Patterns” u.a. von Erich Gamma. Damals bezog sich das Pattern noch auf GUI-basierte Programme, z.B. ein Texteditor.

Mit der Verbreitung des Web wurde dieses Pattern auch auf die Webwelt portiert. Obwohl das Pattern schon so lange bekannt ist, trifft man in der Entwicklerwelt trotzdem oft auf Menschen, denen das Muster nichts sagt. Mit diesem Beitrag möchte ich das Pattern aufarbeiten, um es in späteren Beiträgen (z.B. für das Zend Framework) als Grundlage gebrauchen zu können.

Um das Pattern zu verstehen, ist es am besten vorher zu erfahren, was die Abkürzung bedeutet. Das M steht für das Model, V für den View und das C für den Controller. Die Langversion lautet also Model-View-Controller Pattern. Nachfolgend werde ich die einzelnen Ebenen und deren Zusammenspiel erläutern.

Das Model
In allen drei Schichten muss man im Grunde etwas weiter ausholen, so auch beim Model. Das Model dient allgemein dazu die reale Welt – genauer gesagt Teile davon – in einer gewissen Form abzubilden. In der Softwareentwicklung wird dafür ein oder mehrere Diagramme des Problembereichs erstellt. Diese Diagramme dienen später als Plan, um die Objekte bzw. Datenstrukturen zu erstellen.

Diese Daten und ihre Strukturierung stellen das Model dar. Man könnte diese Ebene vereinfacht auch als Datenbehälter bezeichnen. Nehmen wir doch einfach ein konkretes Beispiel. Ich möchte mein Auto modellieren. Mich interessieren dabei die Marke, die PS Angabe und die Höchstgeschwindigkeit. Dazu erstelle ich eine Klasse “Auto” mit den Klassen-Attributen “marke”, “ps” und “maximalgeschwindigkeit”. Das Model ist nun fast fertig. Das einzige, was es noch benötigt sind sogenannte Getter- und Setter-Methoden. Diese brauchen wir, um einem Objekt der Klasse Auto Daten hinzufügen zu können und ebenfalls diese Daten wieder auszulesen.

Der View
Der View ist mitunter am einfachsten zu erklären. Er stellt die Sicht auf das Model dar. D.h. die Daten des Models werden hier auf dem Bildschirm visualisiert. In der Web-Welt ist es die (ausgelieferte) Webseite, die der Benutzer am Ende zu sehen bekommt. Zusätzlich ist der View die Schnittstelle zwischen System und Benutzer. Der Benutzer interagiert also auf der View-Ebene, z.B. durch Formulare oder durch das Klicken eines Links.

Der Controller
Der Controller ist als Steuerungseinheit zu verstehen. Der Idee nach wissen Model und View am Anfang nichts voneinander. Die Anfrage eines Clients (Web-Browser des Benutzers) an einen Server wird vom Controller entgegen genommen. Dieser Wertet die Anfrage aus.

Nehmen wir nochmals das Beispiel aus dem Model-Abschnitt. Der Benutzer möchte nun erfahren, welches Auto ich fahre und klickt entsprechend auf einen Link. Der Controller erkennt nun diese Anfrage und bereitet das Model auf. Dazu erstellt er ein Auto-Objekt und setzt die Daten auf “Suzuki”, “92″ und “180km/h”. Das Model ist damit gefüllt. Jetzt entscheidet der Controller noch, dass die Seite für das Auto angezeigt werden soll, das ist der View.

Würde die Seite jetzt ausgeliefert werden, wäre leider nichts sichtbar, da der View ja nach wie vor nichts vom Model weiß. Auch dies erledigt der Controller. Verinfacht gesagt teilt er dem View mit “Benutzer bitte dieses Auto-Objekt zum Anzeigen”.

Dadurch, dass der View nun das Auto-Objekt kennt, kann er über die Getter-Methoden des Models auf die Daten zugreifen.

Einige Grundsätze fehlen bei dieser recht einfachen Beschreibung des MVC-Pattern:

  1. Der View manipuliert keine Daten des Models
  2. Das Model ist das ahnungsloseste der drei Ebenen und darf nicht mit sicht auf den View oder den Controller entwickelt werden
  3. Der Controller füllt in den meisten Fällen nicht die Daten des Models, sondern veranlasst das Laden aus der Datenbank (Stichwort Data-Access-Objects)

Feb 3 2010

Die Klassifikationsbaum-Methode für Testfallermittlung

Die grundsätzliche Idee der Klassifikationsbaum-Methode is es den Eingabedatenraum des Testobjektes nach verschiedenen Test relevanten Gesichtspunkten jeweils getrennt voneinander in Klassen, die auch als Äquivalenzklassen verstanden werden können, zu zerlegen. Aus der Kombination geeigneter Klassen werden Testfälle ermittelt. Die Hauptinformationsquelle zur Findung der Klassen ist dabei die Spezifikation, die das geforderte Verhalten des Testobjektes beschreibt.

Der Tester kann durch die Automatisierung einzelner Aktivitäten bei der Testfallermittlung geleitet werden. Des Weiteren bietet die Klassifikationsbaum-Methode eine Möglichkeit zur grafischen Notation, die eine Visualisierung der Testfallermittlung unter Verwendung moderner grafischer Oberflächen ermöglicht. Nachfolgend möchte ich die Methode zunächst allgemein beschreiben und danach zum besseren Verständnis an einem Beispiel verdeutlichen.

Die Ermittlung der Test relevanten Aspekte erfolgt meist manuell durch den Tester mittels der funktionalen Spezifikation des Testobjektes. Diese dienen der einfachen Unterscheidung der möglichen Eingabedaten. Im Anschluss wird die Menge aller möglichen Eingaben unter dem jeweiligen Aspekt disjunkt in Klassen zerlegt. Alle Werte einer Klasse sind demzufolge äquivalent (bei Interesse kann man sich zusätzlich meinen Beitrag zu Äquivalenzklassen durchlesen). Im konkreten Testfall reicht ein Repräsentant aus. Die Zerlegung unter den Aspekten sind Klassifikationen.

In komplexen Systemen werden Klassen mit Hilfe vo Klassifikationen wiederum in weitere Klassen unterteilt. Das rekursive Vorgehen resultiert in einem Klassifikationsbaum, der die anschaueliche Darstellung der mehrstufigen Zerlegung repräsentiert. Klassifikationen werden in der grafischen Darstellung des Baumes als benannte Rechtecke dargestellt. Darunter werden jeweilige Klassen angeordnet. Entsprechend werden die tiefer liegenden Klassifikationen mit ihren Klassen jeweils unter der zugehörigen Klasse notiert.

Im letzten Schritt der Methode werden die Testfälle gebildet. Aus der Kombination verschiedener Klassifikationen entsteht jeweils ein Testfall. Dieser wird in Form einer Zeile in einer Kombinationstabelle notiert. Die Namen der Spalten dieser Tabelle resultieren aus den Blättern (Klassen) des Baumes. Bei logisch unvereinbaren Kombinationen (z.B. Klassen ein und derselben Klassifikation) bleibt der Tabelleneintrag leer.

Die Ermittlung der Test relevanten Aspekte ist oft vom Tester abhängig. Genauer kommt es hierbei auf Kreativität und Verständnis des Problembereichs an. Dadurch ergibt sich die Möglichkeit, dass Fehler im Testobjekt aufgrund unvollständiger Klassifikationsbäume unerkannt bleiben.

Die Methode soll am folgenden Beispiel veranschaulicht werden: Ausgangspunkt ist eine Spezifikation einer Computer-Vision-Systems, welches mit einer Kamera verschiedene Objekte erkennen soll. Mögliche Test relevante Aspekte können hierbei Farbe und Form sein. Damit ergeben sich die KLassifikationen für Farbe und Form. Die Klassifikation Farbe lässt sich beispielhaft in drei Klassen unterteilen: Rot, Gelb und Blau. Bei der Form könnte das Objekt exemplarisch in Kreis, Dreieck oder Rechteck unterteilt sein. Zur Repräsentation einer tiefer liegenden Klassifikation wird die Art eines Dreiecks betrachtet. Hierbei wird zwischen gleichseitigen, gleichschenkligen und ungleichseitigen Dreiecken unterschieden. Mit Hilfe des Klassifikationsbaums können nun Testfälle bestimmt werden.


Feb 3 2010

Basics zu regulären Ausdrücken

Um ehrlich zu sein war dieses Thema für mich früher immer abschreckend. Dazu kommt, dass ich nie wirklich Lust hatte mich damit auseinanderzusetzen. Nachdem ich nun von Zeit zu Zeit dazu gezwungen war das Thema anzugehen, hatte sich herausgestellt, dass reguläre Ausrücke gar nicht so schlimm sind, wie ich Anfangs dachte. Dieser Beitrag soll euch also helfen den Einstieg in diese Thematik zu finden.

Was sind denn un reguläre Ausdrücke? Nun, um es einfach zu sagen, ein regulärer Ausdruck ist eine Zeichenkette. Diese Zeichenkette beschreibt eine Menge an Zeichenfolgen. Klingt verwirrend, ist es aber gar nicht, wenn man sich klar macht, was dies bedeutet. Sagen wir mal, dass wir einen regulären Ausdruck haben, der folgendermaßen aussieht: Fünf mal ein a und danach 3 mal ein b. Die Menge aus Zeichenfolgen sieht nun so aus: aaaaabbb. Schwierig zu verstehen sind reguläre Ausdrücke deshalb, weil sie nicht in der Form, so wie ich es aufgeführt habe, notiert werden. Die Notation beschränkt sich auf sogenannte Meta-Characters (welche mich im Übrigen lange davon abgehalten haben mit ihnen zu arbeiten): ]($^., usw. usw. usw. Ich werde nun einige davon vorstellen, damit ihr nachher (falls ihr sie später seht) sofort sagen könnt “Ah, stimmt ja, das war ja dieses Zeichen und es bedeutet das und das!”

Character Class “[ ]“
Die wunderschönen eckigen Klammern [ ] bieten die Möglichkeit einen Character aus der Klasse (einer Menge an Charactern) zu matchen. Dazu ein kleines Beispiel. Ich möchte die Wörter hot und hat in einem bestimmten Text finden. Ausgeschrieben bedeutet meine Anforderung: Suche ein h gefolgt von einem o oder einem a. Der letzte Buchstabe ist ein t. Als regulärer Ausdruck sieht das nun so aus: h[oa]t.

Character Class Bereiche “-”
Bei einer Character Class existiert auch die Option Bereiche festzulegen. Nehmen wir mal an, ich möchte eine Zeichenfolge haben, die mit einer Zahl aus dem Bereich 1-9 beginnt und von einem der Buchstaben a,b oder c gefolgt wird. Mit der weiter oben beschriebenen Methode würde sich nun [0123456789][abc] anbieten. Mit den Bereichen ist dies allerdings um einiges einfacher zu realisieren: [0-9][a-c]. Zu beachten ist an dieser Stelle, dass der Bindestrich nur innerhalb der eckigen Klammern als “Metacharacter” erkannt wird. Ausserhalb ist der Binderstrich nur ein normales Zeichen.

Metacharacter Dot “.”
Der Punkt ist eigentlich am einfachsten zu erklären. Er bietet euch die Möglichkeit gegen ein beliebiges Zeichen zu matchen. Ein wenig tricky ist der Punkt, weil er nur ausserhalb von Character Klassen als Metacharacter erkannt wird. Aber wenn man dies im Hinterkopf behält, ist auch das ein sehr geringes Problem.

Metacharacter Optional “?”
Das Fragezeichen markiert ein Zeichen als optional. Wozu könnte dies nun gut sein? Schauen wir uns doch mal das Wort schifffahrt an. Ich habe es mal direkt mit drei “f”s geschrieben. Es gibt aber auch eine nicht zu kleine Gruppe an Personen, die das Wort mit nur zwei “f”s schreiben (kommt natürlich auf die gerade gültige Rechtschreibung an). Ich möchte dieses Wort nun in einem Text wiederfinden, egal ob es nun mit zwei oder mit drei “f”s geschrieben ist. Im Klartext: Ich möchte das dritte “f” als optional markieren. Der dazugehörige reguläre Ausdruck sieht nun so aus: schifff?ahrt. An und für sich eine recht komplexe Aufgabenstellung, die mit einem regulären Ausdruck ganz geschickt lösbar ist, dank Metacharacter “?”.

Metacharacter Alternative “|”
Wer aus dem “Programmierer-Bereich” kommt, wird dieses Zeichen sehr gut kennen. Der senkrechte Strich signalisiert, dass es hier Alternativen gibt (die ODER Verküpfung). Deutlich wird dies am Wort dass, welches wir aber auch so schreiben könnten: daß. D.h. wir möchten eine Zeichenfolge haben, die mit einem d beginnt, von einem a gefolgt wird und danach entweder das doppel-s oder ein scharfes s enthält. Der reguläre Ausdruck da(ss|ß) kann uns bei dieser Aufgabenstellung helfen. Die runden Klammern grenzen den Umfang der Alternativen ein.

Man könnte nun recht lange fortfahren. Da dieser Beitrag nur ein kleiner Einstieg in die Thematik sein sollte, werde ich an dieser Stelle auf weitere Beispiele verzichten und hoffe, dass es euch Spaß gemacht hat zu lesen und weiterhelfen konnte.


Feb 3 2010

Migration PHP 5.2 auf 5.3

Im Rahmen meiner Recherche möchte ich hier einige Tipps zur Migration von PHP 5.2.x auf 5.3.x liefern. Das Besondere bei dieser Migration ist die Tatsache, dass PHP 5.3.x nicht abwärtskopatibel mit 5.2.x ist. In einer gewissen Hinsicht erscheint dies auch logisch, da die neue PHP Version bei Abwärtskompatibilität eher einer weitere 5.2.x, als eine 5.3.x Version wäre.

Woaruaf sollte man nun also achten? Dieser Frage möchte ich mich in diesem Beitrag widmen. Eine etwas positive Nachricht zuerst: Falls man bisher schon bei der Programmierung auf Aktualität geachtet hat, wird man bei der Migration recht wenig zu tun haben. Andersherum sieht man sich ums größeren Problemen gegenüber je mehr man sich den älteren 5.2 Versionen gewidmet hat.

Deprecated
Fangen wird doch mit etwas recht einfachem an. PHP bitet seit 5.3 die Möglichkeit auch E_DEPRECATED Warnings auszugeben. In vielen Fällen ist das sehr nützlich. So haben auch die Entwickler der 5.3 Version einige PHP-Methoden als deprecated markiert. D.h. diese Methoden soll man in Zukunft nicht mehr verwenden. In den meisten Fällen wird jeweils auf den passenden Ersatz hingewiesen. Man kann an dieser Stelle recht einfach migrieren indem man den eigenen Code nach diesen Methoden durchsucht:

  • call_user_method()
  • call_user_method_array()
  • define_syslog_variables()
  • ereg()
  • ereg_replace()
  • eregi()
  • eregi_replace()
  • set_magic_quotes_runtime()/magic_quotes_runtime()
  • session_register()
  • session_unregister()
  • session_is_registered()
  • set_socket_blocking()
  • split()
  • spliti()
  • sql_regcase()

Reservierte Keywords
Das nächste Problem sollte in den meisten Fällen auch ohne große Anstrengung zu bewältigen sein. Seit 5.3 gibt es nämlich zwei weitere reservierte Keywords:

  • goto
  • namespace

Durchsucht man also den eigenen Code nach diesen Keywords, dürfte man recht schnell feststellen, ob dieser Migrationsschritt erfolgreich durchgeführt werden kann.

Methoden mit Array-Parameter
Einige Methoden, die vor 5.3 noch Objekte und Arrays gleicherweise als Parameter akzeptiert haben erwarten nun einzig und allein Arrays als Parameter. Das bedeutet, dass man zunächst prüfen sollte, ob eine der Methoden im eigenen Code verwendet wird und falls dem so ist überprüfen muss, ob der übergebene Parameter ein Objekt ist. Dieses Objekt muss in dem Fall zunächst zu einem Array umgewandelt werden. Es handelt sich dabei um folgende Methoden:

  • natsort()
  • natcasesort()
  • usort()
  • uasort()
  • uksort()
  • array_flip()
  • array_unique()

Feb 2 2010

Xbox360 Spiele unter Linux brennen

An dieser Stelle möchte ich ein – wie ich festgestellt habe – heisses Gebiet thematisieren. Zunächst ist allerdings ein Vorwort notwendig: Überlegt es euch bitte gut diesen Schritt zu gehen. Ich persönlich habe im Grunde nur aus Langeweile einen Versuch gestartet, ob es auch so einfach funktioniert, wie ich es im Internet nachlesen konnte. Ja, es ist so einfach, allerdings bedenkt, dass Ihr den Spieleherstellern erheblichen Schaden hinzufügt und damit evtl. verhindert, dass Nachfolger von guten Spieleserien produziert werden.

Nun zum Thema selbst. Ausprobiert habe ich das Ganze unter Ubuntu 9.10 über die Konsole. Wer nach einer Lösung mit GUI sucht, wir dhier zwar nicht fündig, sollte diese Methode allerdings trotzdem einfach mal ausprobieren.

Realisieren kann man den Brennvorgang mit dem Linux.Kommando growisofs über die Konsole.  Dazu muss man vorerst einige Dinge in Erfahrung bringen. Zum einen, den Pfad wo euer Image liegt und zum anderen unter welchem Namen euer DVD-Brenner gemountet (im System eingehbunden) ist. Das erstere traue ich jedem, der das cd Kommando beherrscht zu (oder, wer faul ist, nutzt find  -name). Das Laufwerk findet man heraus, indem man in das Verzeichnis /dev/ wechselt und den ls Befehl mit -l als Parameter ausführt.

cd /dev/; ls -l

In dieser Liste sollte sich nun irgendwo der Name cdrom0 oder dvdrw wiederfinden. In der Regel (bei einem DVD-Brenner) heisst der Brenner sr0. Mit den informationen wechselt man nun (am besten) in das Verzeichnis der .iso Datei.

cd /pfad/zu/deiner/isodatei/

Ab hier ist es unglaublich einfach. Legt den DVD-Rohling in euer Laufwerk und führt den folgenden Befehl aus:

growisofs -speed=2 -dvd-compat -Z -use-the-force-luke=dao -use-the-force-luke=break:1913760 /dev/{{laufwerksname}}={{isoname}}.iso

In dem Befehl ersetzt Ihr noch die geschweiften Klammern. Die erste durch den Namen eures Laufwerks. Die zweite durch den Namen der Isodatei. Im Ergebnis dann in etwa so:

growisofs -speed=2 -dvd-compat -Z -use-the-force-luke=dao -use-the-force-luke=break:1913760 /dev/dvdrw=mygame.iso

Das wars. Ab hier sollte ein Fortschritt in Prozent und die Brenngeschwindigkeit angezeigt werden. Ihr seht, es ist recht einfach. Aber nochmals, ich rate euch dringend davon ab Spiele zu kopieren. Es ist nicht nur illegal, sondern auch schädlich für die Spielehersteller. Zudem übernehme ich keine Verantwortung/Haftung für mögliche Schäden (z.B. verbrannte Rohlinge).


Feb 2 2010

Äquivalenzklassenbildung mit Grenzwertanalyse

Die Grenzwertanalyse stellt einen Spezialfall bzw. Verfeinerung der Äquivalenzklassenbildung dar. Bei dieser Technik werden durch Grenzwerterzeugung zusammenhängende Wertebereiche getestet. Im Gegensatz zur reinen Äquivalenzklassenbildung werden hierbei jedoch nicht beliebige Werte als Repräsentanten einer KLasse gewählt, sondern vorzugsweise die Randbereiche.

Es genügt den unteren Grenzwert sowie den nächstkleineren Wert, den oberen Grenzwert sowie den nächstgrößeren Wert und einen Mittelwert zu generieren, um einen geschlossenen Wertebereich zu testen. Diese Werte sind stellvertretend für alle weiteren innerhalb und außerhalb des jeweiligen Wertebereichs. Ein kleines Beispiel dazu findet ihr im vorangegangenem Beitrag über Äquivalenzklassen.


Feb 1 2010

Basics zu Äquivalenzklassen (Methoden zur Testfallreduzierung)

Die Äquivalenzklassenbildung ist eine Technik, die zur Reduzierung der Anzahl an Testfällen verwendet wird. Hierbei werden die möglichen Werte einer Eingabegröße in Klassen eingeteilt. Dadurch kann durch eine relativ kleine Anzahl an Testfällen eine angemessene Testabdeckung erzielt werden.

Eine Äquivalenzklasse besteht aus einer Menge an Daten, welche als äquivalent angesehen werden, d.h. sie liefern erwartungsgemäß bei einem Test dieselben Ergebnisse. Jeder Datenwert innerhalb einer Äquivalenzklasse ist also so gut wie jeder andere. Die Datenwerte können dabei entweder aus tatsächlichen Wertebereichen, wie z.B. 0 bis 100, oder aus Mengen an Datensätzen bestehen. Für den Test bietet dies folgende Erkenntnisse (nachzulesen in A Practitioner’s Guide to Software Test Design – Copeland, L., 2003):

  1. Falls ein Testfall einer Äquivalenzklasse einen Fehler aufdeckt, so decken auch alle anderen Testfälle der Äquivalenzklasse den Fehler auf.
  2. Falls ein Testfall einer Äquivalenzklasse keinen Fehler aufdeckt, so decken auch alle anderen Testfälle der Äquivalenzklasse keine Fehler auf.

Interessant ist also die tatsächliche Wahl der äquivalenten Daten einer Äquivalenzklasse. Allgemein betrachtet ergeben sich zwei Möglichkeiten:

  1. Verwendung von gültigen Wertebereichen (Testing-by-contract)
  2. Verwendung von ungültigen Wertebereichen (Defensive testing)

Bei dem Testing-by-contract Ansatz geht man davon aus, dass der zu testende Softwareteil (auch Modul genannt) nur Eingabeparameter erhält, welche es verarbeiten kann. Zudem werden dem Modul unabhängig von der Eingabe Daten zur Verfügung gestellt, welche es zur fehlerfreien Verarbeitung der Eingabeparameter braucht. Entsprechend werden hierbei nur Äquivalenzklassen mit gültigem Wertebereich erstellt und durch ihre Repräsentanten getestet.

Äquivalenzklassen mit Daten außerhalb des zulässigen Bereichs werden hierbei nicht berücksichtigt, weil man evtl. davon ausgeht, dass die unzulässigen Bereiche nicht erreicht werden. Problematisch ist bei diesem Ansatz die Tatsache, dass Probleme auftreten könne, sobald ein unzulässiger Bereich in einem ausgelieferten Produkt tatsächlich erreicht wird (z.B. das Jahr 2000 bei einer 1985 geschriebenen Software). Um diesem Problem entgegenzuwirken, werden beim defensive-testing Ansatz auch unzulässige Bereiche zugelassen. Dies bedeutet, dass neben einer Äquivalenzklasse im gültigen Bereich auch mindestens eine Äquivalenzklasse für den ungültigen Bereich erstellt werden und durch einen Repräsentanten getestet werden muss. Die Anzahl nötiger Testfälle erhöht sich zwangsläufig.

Ein kleines Beispiel dazu:

Man hat ein Softwaremodul, das die Wurzelfunktion implementiert und nur ganze Zahlen im Bereich 0 bis 64 akzeptiert. Beim Testing-by-contract Ansatz benötigt man (grob betrachtet) zwei Äquivalenzklassen mit entsprechenden Repräsentanten. Eine davon nennen wir mal die Ganzzahl-Äquivalenzklasse und die andere Dezimal-Äquivalenzklasse. Wir gehen davon aus, dass die Ganzzahl-Äquivalenzklasse alle Eingabeparameter enthält, bei denen das Modul als Ergebnis eine Ganzzahl liefert, z.B. 4 oder 16. Hieraus wählen wir einen Repräsentanten, die 16, was dem ersten Testfall entspricht. Für die zweite Äquivalenzklasse nehmen wir entsprechend die 17, da hier bekannt ist, dass keine Ganzzahl als Ergebnis zu erwarten ist.

Beim defensive-testing werden nun weitere Äquivalenzklassen hinzugefügt. Wir erwarten z.B., dass das Modul bei der Eingabe einer negativen Zahl, einer Dezimalzahl oder einer Zahl größer 64 eine Fehlermeldung liefern muss. Mit der Bildung der entsprechenden Äquivalenzklassen (Negativ-Äquivalenzklasse, Dezimaleingabe-Äquivalenzklasse und Zugroßeeingabe-Äquivalenzklasse) erhält man drei weitere Testfälle: z.B. (-1|0,3|65) oder (-5|20,1|1200). Das erste Beispiel wird sicherlich öfter Anklang finden, da beim Testen versucht wird auch die Grenzbereiche (0/64) ausreichend zu testen.


Feb 1 2010

Testfallermittlung beim Black-Box-Test

In meinem Beitrag über die Testfallermittlung beim White-Box-Test habe ich bereits einige Informationen zu Testmethodiken (z.B. Vor-/Nachteile) erfasst. Dies möchte ich in diesem Beitrag auch für den Black-Box-Test nachholen.

Der Black-Box-Test ist nämlich im industriellen Einsatz deutlich bedeutender als der White-Box-Test. Hierbei ist keine notwendige Kenntnis über die internen Abläufe und Ausführungspfade der Software notwendig. Ebenso werden hierbei auch Implementierungsdetails, wie z.B. IF-Anweisungen außer Acht gelassen. Entscheidend ist bei dieser Testvariante die Kenntnis über das, was die Software im Endeffekt leisten soll.

Ein Black-Box-Test sieht in allgemeiner Form wie folgt aus: Im ersten Schritt erfolgt eine genaue Analyse der Anforderungen oder der Spezifikation, z.B. mit Hilfe des Pflichtenheftes oder technischer Datenblätter. Anhand der gewonnenen Erkenntnisse werden Eingabeparameter ausgewählt und erwartetet Ergebnisse/Ergebniswerte definiert oder generiert. Oft werden die Eingabeparameter so gewählt, dass möglichst große Wertebereiche oder spezielle Grenzwerte abgedeckt werden. Zu beachten ist hierbei , dass bei einem Black-Box-Test nicht unbedingt alle implementierten Eigenschaften der Software allein anhand der Spezifikation erkannt werden können. Die gewählten Parameter verwendet man zur konkreten Testfalldefinition. Die Testfälle dienen als Grundlage für den eigentlichen Test. Nach jedem Testdurchlauf erfolgt die Überprüfung der Ergebnisse mittels der vordefinierten erwarteten Werte.

Der Black-Box-Test bezieht seine Vorteile aus der Tatsache, dass der Tester die Testfälle nach seinem Verständnis der Software gestalten muss und dadurch Testfälle erzeugt, die im Vergleich zu willkürlich gewählten deutlich effektiver und effizienter Fehler aufdecken können. Kritisch ist bei dieser Sichtweise wiederum der Tester selbst. Denn bei einem Black-Box-Test ist es nahezu unmöglich alle Kombinationsmöglichkeiten an Eingabeparametern abzudecken. Es bleibt also dem Tester überlassen, welche Testfälle ausgewählt werden. Diese Teilmenge fällt im Vergleich zu den Variationen sehr klein aus. Wie erfolgreich oder effizient der Test ist, hängt folgerichtig stark mit der Erfahrung des Testers, der Genauigkeit der Spezifikation und der gewählten Testfälle zusammen. Des weiteren ist Software nicht immer schlicht als Ein- und Ausgabe Maschine zu betrachten. Entscheidend sind auch die Zustände, in der sich eine Software befinden kann. Ein solches Universum an Zuständen, Eingabeparametern und erwarteten Ergebnissen ist nicht immer einfach zu überblicken.

Repräsentativ für den Black-Box-Test stehen folgende Methodiken: Äquivalenzklassen, Grenzwertanalyse, Ursache-Wirkungsgraph, Error Guessing


Feb 1 2010

Testfallermittlung beim White-Box-Test

Im Rahmen dieses Beitrags möchte ich euch einige Tipps zur Testfallermittlung beim White-Box-Test an die Hand geben. Für mich war es bisher immer nützlich sich diese Informationen vor Augen zu führen. Ich hoffe, dass es möglichst effizient zusammengetragen ist, die wesentlichsten Teile dabei sind und die Informationen hilfreich sind.

Zunächst einmal kann man sich natürlich fragen, worauf es beim White-Box-Test ankommt. Beim ablaufbezogenen Testen (White-Box-Test) wird das Programm gegen sich selbst getestet. Das Objekt des Testfalls ist der Ablaufgraph des jeweiligen Programms. Bei dieser Methode werden die Testfälle mit Kenntnissen über die innere Funktionsweise und der Spezifikation entwickelt.

Das Ziel ist es, die Überdeckung der möglichen und relevanten Pfade eines Programms in einem Test oder einer Testserie festzustellen.  Die Anweisungen, Zweige und Pfade lassen sich durch eine statische Analyse aus dem Programm ableiten. Bei der dynamischen Analyse des Ausführungen registriert und protokolliert.

Der Nachteil des White-Box-Test ist, dass nur eine bestimmte Klasse von Fehlern durch sie aufgedeckt werden – nämlich grobe Abbruchfehler, unerreichbare Zweige, Irrpfade, endlose Schleifen und unvollständige bzw. inkonsistente Bedingungen. Vergessene Funktionen, unberücksichtigte Daten, inkonsistente Schnittstellen, Tippfehler, IO-Fehler und Abweichungen von der Spezifikation können auch nach Ausführung aller Pfade, d.h. Überdeckung des Ablaufgraphs, unerkannt bleiben.

Den Hauptnutzen zieht der White-Box-Test daraus, dass er den Tester zwingt, sich intensiv mit dem zu testenden Objekt auseinander zu setzen. Dabei stößt dieser unwillkürlich auf logische Ungereimtheiten, da er stets bestrebt ist alle Anweisungen, Pfade und Zweige auszuführen.