Analytische Qualitätssicherung 

 1. April 2014

Prüfen und Messen von Softwareartefakten

Die analytische Qualitätssicherung bietet eine kosten- und ressourcenschonende Möglichkeit, um Softwareartefakte – beispielsweise Anforderungen, UML-Diagramme, Quellcode und Testfälle – nach vorgegebenen Regeln zu prüfen und nach Kriterien wie Komplexität, Qualität und Quantität zu vermessen. Durch den Einsatz der analytischen Qualitätssicherung können Fehler somit frühzeitig gefunden und behoben werden.

Ansätze zur SoftwareQualitatssicherung

Zur Sicherung der Qualität von Software bieten sich die folgenden fünf Ansätze an (vgl. 1):

  • psychologisch
  • konstruktiv
  • analytisch
  • empirisch
  • nachträglich

Zum psychologischen Ansatz gehören alle Maßnahmen zur Beeinflussung der Menschen, qualitativ besser zu arbeiten, also Maßnahmen wie Belohnung, Bestrafung, Beförderung und Appelle an die Arbeitsethik. Zum konstruktiven Ansatz gehören alle Maßnahmen zur Besserung der Arbeitsbedingungen – wie die Bereitstellung besserer Arbeitsmittel – Werkzeuge, Sprachen, Techniken, Prozesse usw. – sowie die Bereitstellung möglichst moderner Arbeitsplätze – Räumlichkeiten, Kommunikationsinfrastruktur, Werkzeuge, soziales Netzwerk und dergleichen.
Zum analytischen Ansatz gehören alle Maßnahmen zur Kontrolle jener Softwareartefakte, die von den Softwerkern produziert werden – das Prüfen und Messen der Dokumente, Modelle, QuellcodeTexte und Testfälle – mit dem Ziel, Qualitätsmängel und Abweichungen vom Soll zu erkennen und die Verfasser der Artefakte darauf aufmerksam zu machen.
Zum empirischen Ansatz gehören alle Testmaßnahmen wie Unit-Test, Integrationstest, Systemtest und Abnahmetest. Hier wird das Verhalten der fertiggestellten Software in einer Testumgebung unter kontrollierten Bedingungen beobachtet, um Abweichungen vom Sollverhalten zu erkennen.
Zum nachträglichen Ansatz gehören alle Maßnahmen, die dazu dienen, die Qualität der Softwareartefakte nach deren Fertigstellung nachträglich zu steigern – Maßnahmen wie Re-Engineering, Refactoring und Re-Implementierung. Im Gegensatz zur Beseitigung einzelner Mängel und Fehler durch den Entwickler der Software im Rahmen der Entwicklung, geht es hier um gezielte Aktionen, bezogen auf ein ganzes System oder Teilsystem mit dem Ziel, die Qualität jenes Systems zu steigern.
Dabei wird davon ausgegangen, dass der Grad der Qualitätssteigerung sich messen lässt.In diesem Beitrag gehen wir auf den dritten, den analytischen Ansatz, ein. Die anderen vier Ansätze sind ebenso wichtig und sollten parallel zu diesem verfolgt werden, aber jeder dieser Ansätze enthält genug Stoff für ein eigenes Buch.

Der Unterschied zwischen Mängeln und Fehlern

Ehe wir auf die analytischen Maßnahmen eingehen, ist es zunächst notwendig, die beiden Begriffe „Mangel“ und „Fehler“ (Deficiencies und Defects, vgl. 2) zu unterscheiden. Ein Mangel ist die Verletzung einer Qualitätsregel, eine Abweichung von der Norm. Die Regel könnte sein, dass Codebausteine nicht mehr als dreifach verschachtelt werden dürfen oder dass jeder Eingangsparameter auf seine Plausibilität geprüft werden sollte.

Ein Mangel wird das Verhalten eines Softwareprodukts nicht unbedingt beeinträchtigen. Es gibt schon Mängel, die sehr wohl zu einem Fehler führen können, z.B. wenn Ausnahmebehandlungen oder Sicherheitsprüfungen im Code fehlen oder wenn Anwendungsfälle nicht vollständig spezifiziert sind. Die meisten Mangelarten werden aber nur die Wartung und Weiterentwicklung der Software beeinträchtigen, z.B. wenn die Codebausteine zu eng miteinander gekoppelt sind oder wenn willkürliche Datennamen verwendet werden. Ein jedes Softwareartefakt unterliegt den Gesetzen der Softwareevolution. Um ihren Wert zu behalten und weiter nützlich zu bleiben, müssen sie ständig weiterentwickelt werden. Diese Weiterentwicklung verursacht Kosten. Wer diese Kosten minimieren will, muss dafür sorgen, dass die Software weiterentwicklungsfähig wird und bleibt. Daraus folgen die zwei Ziele der analytischen Qualitätssicherung:

  1. Verhaltensfehler vermeiden
  2. Weiterentwicklungskosten verringern

Fehler sind – im Gegensatz zu Mängeln Probleme mit dem Verhalten der Software. Das heißt, die Software verhält sich anders, als erwartet. Entweder bricht die Software ab oder sie produziert falsche Ergebnisse. Solches Fehlverhalten lässt sich nur erkennen, wenn die Software ausgeführt wird. Darum wird Testen der empirische Ansatz zur Qualitätssicherung genannt. Die Software wird ausgeführt, um ihr Verhalten empirisch zu untersuchen. Dabei geht es immer um einen Abgleich. Das Ist-Verhalten wird mit dem Soll-Verhalten verglichen und jegliche Abweichung wird zunächst als Fehler betrachtet.

Verursacht werden Fehler durch Unzulänglichkeiten im Code bzw. in der Konstruktion – so genannte Defects. Es kann aber auch sein, dass die Soll-Vorgabe bzw. die Erwartung falsch ist. In diesem Fall ist nicht der Code, sondern die Vorgabe bzw. Erwartung fehlerhaft. Jedenfalls gibt es hier eine Diskrepanz zwischen dem Soll und dem Ist und diese gilt es zu beseitigen. Der Zweck der empirischen Qualitätssicherung ist es, derartige Diskrepanzen aufzudecken, auch was die Performance und die Belastbarkeit der Software anbetrifft. Das Testen ist unumgänglich, ist aber ein Thema für sich und wird hier nicht weiter behandelt.

Analytische Qualitätssicherung = Prüfen + Messen

In der Theorie ist die analytische Qualitätssicherung ein breites, fast grenzenloses Feld. In der Praxis kann es auf wenige automatische Prüfungen reduziert werden. Software besteht in der Regel aus vier Objektarten auf vier semantischen Ebenen:

  • Anforderungsdokumente auf der Spezifikationsebene
  • Entwurfsmodelle (UML/ER) auf der Entwurfsebene
  • Quellcode auf der Codeebene
  • Testfälle auf der Testebene

Anforderungsdokumente und Quellcode sind beides Texte. Hinter den UML-Modellen stecken strukturierte Daten in Form von XML-Dokumenten, in denen die Entwurfselemente und deren Beziehungen festgehalten sind. Aus den XML-Texten werden die UML-Diagramme abgebildet und umgekehrt. Auch die Testfälle werden in Texte umgesetzt, nämlich in Testskripte, die interpretiert oder kompiliert werden, um Testdaten zu generieren und Testergebnisse zu validieren. Zunächst sind die Testfälle aber meistens in Tabellen gespeichert mit Zeilen und Spalten, in denen die TestfallAttribute festgehalten sind.

Bei der analytischen Qualitätssicherung geht es darum, diese vier Textarten zu prüfen und zu messen. Die unterschiedlichen Prüf- und Messmaßnahmen werden hier unter dem Oberbegriff Software-Audit zusammengefasst. Früher wurden sie unter den Bezeichnungen wie „Design-Reviews“, „Code-Inspections“, und „Test-Audits“ manuell durchgeführt (vgl. 3). Der Autor Sneed war selbst Ende der 70er Jahren für die Inspektion von Struktogrammen und Chill-Programmen in dem Siemens EWSD-Projekt (Elektronisches Wählsystem Digital) verantwortlich. Er brauchte circa einen halben Tag, um nur ein Modul zu prüfen. Allein die Code-Inspektion zog sich über ein Jahr hinaus. Heute – im Zeitalter der agilen Entwicklung – kann sich das keiner mehr leisten. Die analytische Qualitätssicherung muss, wie auch die empirische Qualitätssicherung beziehungsweise wie das Testen, automatisiert sein. Die Prüf- und Messobjekte werden aus dem Konfigurationsmanagement-System geholt und dem passenden Werkzeug gleich zugeführt (siehe Abbildung 1).

Analytische Qualitätsicherung
Analytische Qualitätsicherung

Prüfung und Messung der Anforderungsdokumente

Anforderungsdokumente werden mit einem Werkzeug für die automatische Analyse der natürlichen Sprache geprüft und vermessen. Die Texte müssen vorher entweder mit XML-Tags oder mit Schlüsselwörtern markiert werden. Damit das Dokument für den Endbenutzer leichter zu schreiben bleibt, empfehlen sich Schlüsselwörter, denn besser ist es, jene Wörter bzw. Tags gleich von Anfang an in den Text einzubauen, wo sie auch als Wegmarkierer dienen können. Beispielhaft für solche Schlüsselwörter in deutscher Sprache ist die Liste in Tabelle 1.

Typ Bezeichnung
ACT Akteur
CASE Use-Case
INPT Eingabe
MASK GUI
OBJT GO
OUTP Ausgabe
PATH Hauptpfad
POST Nachbedingung
PRE Vorbedingung
PROC Verarbeitet
REFS Implementiert
USES Benutzt
REQU FUNC-REQ
REQU NF-REQ
RULE GR
TRIG Auslöser
Schlüsselworttabelle

Anhand dieser Schlüsselwörter – Keywords in Context – werden die Textelemente erkenntlich gemacht. Außer den einzelnen Anforderungen werden auch Geschäftsregeln, Geschäftsobjekte, Akteure, Schnittstellen, Oberflächen und Anwendungsfälle gekennzeichnet. In einem semiformalen Anforderungstext sollten zuerst die projektübergeordneten Elemente wie Geschäftsobjekte und Geschäftsregeln dokumentiert sein. Danach kommen die projektspezifischen Anforderungen, funktionaler und nicht-funktionaler Art. Es folgen dann die Systemakteure, Systemschnittstellen und Oberflächenmuster. Erst zum Schluss kommen die Anwendungsfälle als Brücke zum Systementwurf. So können die Anwendungsfälle auf die Anforderungen verweisen, die sie erfüllen, auf die Geschäftsregeln, die sie implementieren, auf die Objekte, die sie verarbeiten, auf die Schnittstellen, die sie bedienen, und auf die Akteure, von denen sie angestoßen werden.

Fallbeispiel „Kalenderfunktion“

Folgendes Beispiel dient dazu, eine einfache Anforderungsspezifikation einer Kalenderfunktion zu schildern.

Funktionale Anforderungen

  • FUNC-REQ-01 (Wochentagsermittlung): Der Benutzer gibt ein achtstelliges Datum mit Jahr, Monat und Tag ein und bekommt den Wochentag zurück.
  • FUNC-REQ-02 (Mehrsprachigkeit): Der Wochentag kann wahlweise in deutsch, französisch oder italienisch zurückgegeben werden.
  • FUNC-REQ-03 (Ausrichtung): Der Text des Wochentages kann links oder rechts ausgerichtet sein.
  • FUNC-REQ-04 (Fehlerbehandlung): Sollte es nicht möglich sein, das Datum in einen Wochentag umzusetzen, sollten Fragezeichen „??????“ in dem Antwortsfeld erscheinen.

Nicht-funktionale Anforderungen

  • NF-REQ-01 (Antwortzeit): Die Antwortzeit bei der Kundenabfrage sollte <= 1 Sekunde und die Antwortzeit bei Kundenaufträgen <= 3 Sekunden sein.
  • NF-REQ-02 (Belastbarkeit): Das Service muss in der Lage sein, mindestens 500 Aufträge pro Stunde ohne Performanceverlust zu verarbeiten.
  • NF-REQ-03 Verfügbarkeit: Das Service muss für 24 Stunden pro Tag und an sieben Tagen in der Woche zu mindestens 95 Prozent der Zeit verfügbar sein.

Geschäftsobjekte

  • GO-01: Kalender
  • GO-02: Termine
  • GO-03: Wochentage

Geschäftsregen

  • GR-01: (unplausible Datumsbehandlung): Wenn ein Datum nicht plausibel ist, wird der Wochentag mit „?“ gefüllt.
  • GR-02: Kalenderausgangsdatum: Der Kalender geht davon aus, dass der 1. Januar 1901 einen Dienstag war.
  • GR-03: Sprach-Codes: Im Unternehmen gelten folgende Sprach-Codes: Deutsch = „1” , Französisch = „2” , Italienisch = „3”, Englisch = „4”.

Anwendungsfall
Das Textanalysewerkzeug prüft, ob alle Pflichteigenschaften und Verweise vorhanden und ob sie konsistent sind, z. B.:

  • Anwendungsfall erfüllt keine Anforderung.
  • Anwendungsfall verweist auf undefinierte Anforderung.
  • Anforderung wird von keinem Anwendungsfall erfüllt.
  • Geschäftsregel wird nicht implementiert.
  • Geschäftsobjekt wird nicht referenziert.

Außerdem prüft der Textanalysator, ob alle Anforderungssätze richtig formuliert sind. Chris Rupp und ihre Mitarbeiter von der Sophist GmbH haben Regeln bzw. Prüfungsvorschriften definiert, wie Anforderungssätze zu formulieren sind – das so genannte „Sophist Regelwerk“ (vgl. 4). Danach sollte beispielsweise jede Anforderung eindeutig identifizierbar, zuordenbar und auslegbar sein. Jeder Anforderungssatz sollte Subjekt, Objekt und Prädikat haben und Nominalisierungen (d.h. die Zusammenfassung mehrerer Aktionen in einem substantivierten Verb) vermeiden. Stellvertretend für diese Regelverletzungen sind unter anderem:

  • Aktionen sind passiv formuliert und nicht aktiv.
  • Ein Zustand bezieht sich auf mehrere Objekte, nicht nur auf eines.
  • Ein abstrakter Zustand ist nicht eindeutig definiert.
  • Eine Aussage setzt eine implizite Annahme voraus.

Das Tool SoftAudit kann die Einhaltung solcher Regeln Satz für Satz überprüfen. Schließlich kann der Analysator die Textelemente zählen und eine Anforderungsmetrik aufbauen. Gezählt werden unter anderem die Anforderungen, die Geschäftsregeln, die Objektverweise, die Anwendungsfälle und die Verarbeitungsschritte in den Anwendungsfällen. Darüber hinaus werden auch Function-Points, DataPoints und Use-Case-Points gezählt. Das Ziel ist, die Größe, Komplexität und Qualität der Anforderungsdokumente zu messen.

Attribut Beschreibung
Bezeichnung Wochentagermittlung
Erfuellt Func-Req-01, Func-Req-02,Func-Req-03, Func-Req-04.
Implementiert GR-01, GR-02, GR-03, GR-04, GR-05, GR-06, GR-07.
Funktionen FUNK-01.
Empfaengt REQUEST-01.
Sendet RESPONSE-01.
Verarbeitet GO-01, GO-02, GO-03.
Auslöser Nachricht_vom_Client
Akteure ClientProgramm
Vorbedingungen Client muss berechtigt sein. Datum muss gültig sein.
Nachbedingung Bei Erfüllung Wochentag in Deutsch, Französisch oder Italienisch. Bei nicht Erfüllung Wochentag = ???????.
Hauptpfad 1) Client sendet Nachricht mit Datum.
2) Service prüft Datum.
3) Wenn Datum gültig ist, sucht Service Wochentag in Wochentagtabelle.
4) Falls der Sprachcode 1 ist, holt Service den deutschen Wochentag.
5) Falls der Sprachcode 2 ist, holt Service den französischen Wochentag.
6) Falls der Sprachcode 3 ist, holt Service den italienischen Wochentag.
7) Service gibt gewählten Wochentag zurück.
Nebenpfad 8) Service gibt ?????? zurück.
Ausnahmen Service lehnt Auftrag ab wenn Client nicht berechtigt ist.
Erbt Standard Datumsfunktion.
Benutzt Datumsprüfung
Erweitert Client-Kalender
Kommentare Diese Service gilt nur für einen Datum seit 1900.

Prüfung und Messung des UML-Modells

Für die Prüfung und Messung des Entwurfsmodells benutzt das Werkzeug SoftAudit einen XML-Parser, der das XML-Schema hinter den UML-Diagrammen parst. Beim Parsen des XML-Schemas werden die Modelltypen wie Klassen, Objekte, Methoden, Attribute, Parameter, Aktivitäten und Anwendungsfälle erkannt und gezählt. Gleichzeitig werden die Beziehungsarten wie Assoziation, Vererbung, Nutzung und Inklusion erkannt und ausgewertet. Die Modellkomplexität ergibt sich aus dem Verhältnis der Modellbeziehungen zu den Modellelementen. Je mehr Beziehungen es gibt – relativ zur Anzahl der Elemente –, desto höher ist die Komplexität des Modells:

Formel Modellkomplexität
Modellkomplexität

Die Modellgröße geht aus der Anzahl der Modellelemente hervor. Die Modellqualität ist das Verhältnis vom Ist zum Soll. Jede Klasse soll beispielsweise nur eine begrenzte Anzahl von Abhängigkeiten zu anderen Klassen haben (Kopplungsgrad) und eine begrenzte Anzahl von Attributen relativ zur Anzahl der Methoden (Kohäsionsgrad). Jede Klasse soll mindestens ein Attribut und zwei Methoden haben. In den Sequenzdiagrammen dürfen nur Verweise auf Klassen vorkommen, die bereits in einem Klassendiagramm definiert sind. In den Aktivitätsdiagrammen dürfen nur Schritte eines spezifizierten Anwendungsfalls vorkommen, die wiederrum als Methoden in einem Klassendiagramm definiert sind. Auf diese Weise wird die Konsistenz des Modells geprüft (vgl. 5).

An dieser Stelle folgt auch die erste Querprüfung über semantische Ebenen hinaus. Es kann nämlich geprüft werden, ob alle Geschäftsobjekte in der Anforderungsdokumentation auch als Objekte im Objektmodell auftauchen und ob alle in dem Anforderungsdokument spezifizierten Anwendungsfälle in den Use-Case-Diagrammen vorkommen. Hier lässt sich also die Konsistenz zwischen dem Anforderungsdokument und dem Entwurfsmodell kontrollieren. Typische Mängel im Entwurfsmodell sind:

  • Die Klasse ist referenziert, aber nicht definiert („Class referenced is not defined”).
  • Der Entity-Name entspricht nicht der Namenskonvention („Entity Name does not conform to naming rules“).
  • Die maximal erlaubte Anzahl an Paramentern bei der Methode ist überschritten („Maximum Number of Parameters to a Method is exceeded”).

Aus der Analyse des UML-Modells gehen wiederum zwei Berichte hervor: ein Mangelbericht der Diskrepanzen zwischen Soll und Ist und ein Messbericht mit der Entwurfsmetrik (Größe, Komplexität und Qualität)

Anforderungsmetrik
Anforderungsmetrik

Prüfung und Messung des Codes

Der Quellcode ist das, was am meisten geprüft und gemessen wird. Zu diesem Zweck gibt es bereits etliche Werkzeuge wie „Software Sonar“, „FxCop“ (.NET) und „PMD“ (Java), die nicht weniger als 180 verschiedene Codierungsregeln prüfen. Auch das Tool „SoftAudit“ prüft Quellcode in zwölf verschiedenen Sprachen von IBM Assembler bis hin zu Java und PHP. Manche Regeln für den Code sind abhängig von der jeweiligen Programmiersprache, wie zum Beispiel:

  • Equal Operator ist zu verwenden, um Objekte zu vergleichen.
  • Klassen sollten mit final definiert werden.
  • Methoden dürfen nur über eine definierte Schnittstelle aufgerufen werden.

Andere Regeln gelten für eine bestimmte Klasse von Sprachen, für objektorientierte Sprachen beispielsweise:

  • Klassenattribute sollten nie als public deklariert werden.
  • Data Casting sollte vermieden werden.
  • Methoden sollten nicht mehr als vierfach verschachtelt werden.
  • Verschachtelte Klassen sind zu vermeiden.
  • Jeder Aufruf einer fremden Methode sollte in einen Try-catch-Block eingebettet sein.

Dann gibt es Regeln, die allgemeingültig sind und für alle Sprachen gelten, wie etwa:

  • Bedingungen sollten nicht mehr als drei Klauseln haben.
  • Textliterale dürfen im prozeduralen Code nicht vorkommen.
  • Mehrdimensionale Arrays sind zu vermeiden.

Solche Regeln dienen einem dreifachen Zweck (vgl. 6):

  1. Den Code einheitlich zu gestalten.
  2. Den Code änderungsfreundlicher zu gestalten.
  3. Den Code sicherer zu machen.

Erfahrene Entwickler werden immer einzelne Regeln in Frage stellen – und das ist gut so. Sie liefern damit einen Anstoß, über die bestehenden Regeln nachzudenken und deren Aktualität und Sinnhaftigkeit zu hinterfragen. Am Ende muss sich jedoch eine Entwicklungsmannschaft einigen, welche Regeln für sie gelten sollten.

Designmetrik
Designmetrik

Außer solchen elementaren Anweisungskontrollen gibt es auch Regeln für die Codemodule in ihrer Gesamtheit. Das sind Regeln, um die Größe der Codemodule, die Anzahl der gekapselten Datenattribute und die Anzahl der Beziehungen nach außen einschränken. Diese Regeln fördern die Modularität und die Wiederverwendbarkeit des Codes. Andere Regeln dieser Art sind Regeln für die Begrenzung der Anzahl an Parametern in einer Schnittstelle und die Breite der Sichten auf eine Datenbank. Solche Regeln fördern die Testbarkeit. Regeln für die Kommentierung und die Einrückung verschachtelter Codezeilen sowie für die Einschränkung der Zeilenlängen dienen der Verständlichkeit.

Codierregeln sind also nicht dazu da, die Entwickler zu gängeln, sondern den Entwicklern die Zusammenarbeit zu erleichtern, ebenso wie Verkehrsregeln dazu da sind, den Straßenverkehr zu ordnen. Durch die statische Prüfung des Codes und die Aufdeckung von Regelverletzungen werden viele potenzielle Probleme vermieden. Vor allem wird vermieden, dass die technischen Schulden ins Unermessliche steigen. Robert C. Martin betont in seinem Buch „Clean Code“ die Bedeutung statischer Codeanalysatoren für die Erhaltung der Codequalität (vgl. 7).

Hand in Hand mit der Prüfung des Codes geht die Messung desselben. Es werden Anweisungen, Anweisungsarten, Daten, Datenreferenzen, Objekte und Codeblöcke gezählt. Aus diesen Zählungen werden anschließend Metriken berechnet:

  • Größenmetriken wie Function-Points, Data-Points und Test-Points.
  • Komplexitätsmetriken wie zyklomatische, sprachliche und referentielle Komplexität.
  • Qualitätsmetriken wie Kohäsion und Kopplung, Wiederverwendbarkeit, Sicherheit, Testbarkeit und Wartbarkeit.

Der Grad an Codequalität sollte natürlich auf der rationalen Skala von 0 bis 1 möglichst hoch sein. Der Grad an Komplexität sollte wiederum möglichst niedrig sein. Diese Messwerte sind wichtige Anhaltspunkte für die Bewertung der Software insgesamt und bieten eine Orientierungshilfe für die Nachbesserungsmaßnahmen. Wenn es darum geht, die Qualität des Codes durch Refactoring-Maßnahmen zu verbessern, muss die Qualität des Codes vor und nach den Verbesserungsmaßnahmen verglichen werden. Dies setzt eine Quantifizierung der Qualität voraus.

Vergleichende Code-Metrik
Vergleichende Code-Metrik

Prüfung und Messung der Testfälle

Die längste Zeit wurde die Testware vernachlässigt, obwohl Testfälle für jedes Softwaresystem essenziell sind. Niemand kam auf die Idee, sie zu prüfen oder gar zu messen. Testware wurde nie als Teil des eigentlichen Softwareprodukts angesehen. Sie wird nur in Ausnahmefällen an die Kunden ausgeliefert. Aber dieses Argument gilt auch für die Anforderungsspezifikation und das Entwurfsmodell. Man hat inzwischen eingesehen, dass auch ihre Qualität gesichert werden muss – und dies gilt ebenso für die Testware.

Mit Testware sind die Testprozeduren, Testfälle und Testskripte gemeint, die dazu dienen, das Softwaresystem und seine Bestandteile zu testen. Testskripte sind wie Programmcode. Sie haben eine formale Syntax und lassen sich wie Code parsen. Es gibt auch Regeln dafür, wie sie zu gestalten sind. Das Problem hier ist wie bei den Anforderungen, dass es keine verbindliche Sprachnorm gibt. Jeder Test-Tool-Hersteller bietet eine eigene Skriptsprache an. Nichtdestotrotz kann, wer will, ein Tool schreiben, um Testskripte zu prüfen und zu messen, und für manche Skriptarten gibt es fertige Analysewerkzeuge wie für das WebService-Testskript.

if (operation = "getWeekDay"); if (response = "getWeekDay1Response");       assert out.$ResponseTime < "1100";       if (object = "return");          assert out.P1_TT = "16":          assert out.P1_MM = "10";          assert out.P1_CE = "18";          assert out.P1_JJ = {81:89};          assert out.LANG_CODE = {1:3};          assert out.DIRECTION = "L";          assert out.DAY_NAME = "Mittwoch";          assert out.RETURN_CODE = {1:3};       endObject;    endResponse; endOperation;

SoftAudit setzt voraus, dass Testfälle in einer Excel-Tabelle oder einer relationalen Datenbanktabelle gespeichert sind, in der jede Spalte ein bestimmtes Attribut des Testfalles enthält. Es obliegt dem Benutzer, die Namen und Typen der Testfallattribute festzulegen und sie in einer Parameterliste festzuhalten. Das Prüfwerkzeug benutzt diese Parameterliste, um die Testfalltabelle zu bearbeiten. Davon ausgehend wird geprüft, ob alle Pflichtattribute vorgegeben, ob die Testfälle nach Ziel, Zweck und Typ klassifiziert, ob die Testfälle automatisiert und ob die Testfälle schon ausgeführt worden sind. Dadurch, dass die Testfälle auf Anforderungen oder Änderungsanträge bezogen sind, wird auch geprüft, ob die referenzierten Anforderungen tatsächlich vorhanden sind. Wenn ja, wird ein Link zwischen den Testfällen und den Anforderungen hergestellt. Durch die Invertierung jener Links wird festgestellt, welche Testfälle zu welchen Anforderungen, bzw. Anwendungsfällen und Geschäftsregeln gehören. Es dürfte keine Anforderung bzw. keinen Anwendungsfall ohne Testfall geben. Sämtliche Verbindungen zwischen Testfällen und Anwendungsfällen sowie zwischen Testfällen und Anforderungen werden von dem Tool dokumentiert.

Testmetrik-Bericht
Testmetrik-Bericht

Konsistenzprüfung über alle semantische Ebenen hinaus

Für die Gesamtbewertung eines Softwareprodukts ist es erforderlich, die Prüf- und Messergebnisse sämtlicher Teilprodukte zusammenzufassen. Ein Ganzes ist nur so gut wie die Summe seiner Einzelteile plus aller Beziehungen zwischen den Einzelteilen.

Softwaresysteme sind mehr als nur Code. Sie bestehen aus den Anforderungsdokumenten, den Entwurfsmodellen, den Codeabschnitten und den Testfällen. Diese Schichten müssen vollständig und konsistent sein. Deshalb muss neben der Prüfung einzelner Artefakte eine Prüfung deren Konsistenz stattfinden. Es muss möglich sein, die Codebausteine auf die darüber liegende Architektur und Anforderungsbeschreibung zurückzuverfolgen. Entweder geschieht dies über gemeinsame Bezeichner, über Kommentare, die auf Anforderungselemente hinweisen, oder über die Testfälle. Testfälle verbinden die Codebausteine mit den Anforderungen. Zu jeder Anforderung gehört ein Testfall, der die Erfüllung jener Anforderung bestätigt, und diese Erfüllung findet im Code statt. Die Qualität des Gesamtsystems hängt von der Sichtbarkeit aller internen und externen Abhängigkeiten ab. Daher das Bemühen, jene Beziehungen sichtbar zu machen.

Die Konsistenzprüfung der Software beginnt schon mit der Anforderungsdokumentation. Jede funktionale Anforderung muss von einem Anwendungsfall erfüllt und von mindestens einem Testfall bestätigt werden. Jeder Anwendungsfall muss wiederum von einem oder mehreren Codebausteinen implementiert werden. Jeder Codebaustein bzw. jede Klasse muss mindestens einem Anwendungsfall zugeordnet sein. Allein durch die statische Analyse ist es möglich, diese Verknüpfungen zu erkennen und zu registrieren. Anschließend lassen sich die fehlenden Verknüpfungen als Qualitätsmängel ausweisen. Typische Konsistenzmängel sind:

  • Anforderungen, die durch keinen Anwendungsfall erfüllt sind.
  • Anforderungen, die durch keinen Testfall getestet sind.
  • Anwendungsfälle, die keine Anforderungen erfüllen.
  • Anwendungsfälle, die von keinem Codebaustein implementiert werden.
  • Codebausteine, die keinem Anwendungsfall zuzuordnen sind.
  • Codebausteine, die keine Testfälle haben.

Der zuständiger Tester bzw. Qualitätsprüfer bekommt einen Bericht über die fehlenden Beziehungen im System und kann die Entwickler darauf verweisen, ohne testen zu müssen.

Die Bedeutung der Softwaremetrik

Vollständigkeit und Konsistenz machen die eine Seite der statischen SoftwareQualitätssicherung aus. Sie wird über den Abgleich der Messergebnisse realisiert. Die andere Seite ist die Konformität mit den allgemeinen und produktspezifischen Qualitätsanforderungen. Diese Anforderungen finden ihren Ausdruck nicht nur in den Anforderungsdokumenten, sondern in den zahlreichen Veröffentlichungen zum Thema Softwareentwicklung, in denen 50 Jahre Erfahrung mit dem Bau von Softwaresystemen dokumentiert sind.

Die leidvolle Erfahrung mit zahlreichen schlechten Lösungen zeigt, wie eine gute Lösung auszusehen hat. Die Regeln für eine gute Lösung werden in Metriken formuliert, die eine Art Sollmaßstab für die Software setzen. Ein Metrik ist nicht mehr als eine quantifizierter Erfahrungswert (z.B. sollen Softwarebausteine nur lose gekoppelt sein, damit jeder für sich weiterentwickelt werden kann, ohne die anderen zu beeinflussen, oder Softwareanforderungen sollen so präzise formuliert sein, dass keine Missverständnisse entstehen können). Die viel zitierte zyklomatische Zahl von Tom McCabe ist letztlich nur eine Erfahrungsregel für die Einschränkung der Ablaufkomplexität. Das Gleiche gilt für die anderen Maße wie Vererbungstiefe und Klassengröße. Die Umsetzung solcher Erfahrungswerte lässt sich am besten anhand quantifizierter Maße bewerten (vgl. 8).

Ziel müsste es sein, die Messwerte aus der Analyse aller Softwareartefakt-Typen in einer zentralen Metrik-Datenbank zusammenzuführen und dort einander gegenüberzustellen. Eine derartige Zahlendatenbank benötigt zum einen mehrere Import-Schnittstellen, um die Messwerte aus den unterschiedlichen Analysewerkzeugen aufzunehmen, und zum anderen eine graphische Benutzungsoberfläche, um den Benutzern diverse Sichten auf die Zahlen zu präsentieren. Es geht darum, die Qualität der Software in Zahlen auszudrücken (vgl. 9). Das Metrik-Datenbanksystem des Autors Sneed hat sich zu diesem Zweck bereits in mehreren Bewertungsprojekten bewährt. In diesen Projekten wurden Softwaresysteme mit bis zu drei Millionen Codeanweisungen und 40.000 FunctionPoints geprüft und gemessen, um daraus Schlüsse für die Weiterentwicklung jener Systeme zu ziehen.

Erfahrung mit der analytischen Qualitätssicherung

Viele Entscheidungsträger in der IT stehen dem Thema „statische Softwareanalyse” skeptisch gegenüber. Sie erkennen nicht den Zusammenhang zwischen der Qualität der Systemkonstruktion und der Qualität des Systemverhaltens. Demzufolge konzentrieren sie ihre Aufmerksamkeit und auch ihre Ressourcen auf das, was sie verstehen, nämlich die empirische Qualitätssicherung – Testen nach dem Motto „Probieren geht über Studieren“. Was sie dabei übersehen, ist, dass ein Großteil der Probleme beim Verhalten der Software auf deren Konstruktion zurückzuführen ist. Konstruktionsmängel führen oft zu Verhaltensfehlern. Es ist viel billiger, solche Mängel durch die statische Analyse aufzudecken als in einem aufwändigen Test. Dies unterstreicht Paul Duvall in seinem Buch über „Continuous Integration“ (vgl. 10).

Das andere Ziel der analytischen Qualitätssicherung – die Sicherung der Weiterentwicklung – wird oft gänzlich ausgeklammert. Software-Führungskräfte sind zu sehr mit ihren Tagesproblemen beschäftigt, um einen Blick auf die Zukunft zu werfen.

Dabei übersehen sie, dass die Ursachen ihrer Tagesprobleme größtenteils in der Kurzsichtigkeit der Vergangenheit liegen. Würden sie mehr in die Sicherung der Systemqualität investieren, hätten sie später weniger Probleme mit der Wartung und Weiterentwicklung ihrer Systeme.

Die Mittel zur analytischen Qualitätssicherung sind inzwischen so weit gediehen, dass die Kosten kaum ins Gewicht fallen. Sie sind minimal, verglichen mit dem Nutzen, die solche Analysen mit sich bringen. Es ist daher zu erwarten, dass in Zukunft die analytische Qualitätssicherung immer mehr an Bedeutung gewinnt. Sie wird zwar das Testen nie ganz ersetzen, aber sie kann viele Qualitätsmängel aufdecken, die im Test niemals zum Vorschein kommen.

Der Artikel wurde in der Ausgabe 04/2014 von OBJEKTspektrum veröffentlicht.

  1. H. Sneed, Software Qualitätssicherung, Rudolf Müller Verlag 1988
  2. S.H. Kan, In-Process-Metrics for Software Testing, in: IBM Systems Journal, Vol. 37, Nr. 3, 1998
  3. T. Gilb, D. Graham, Software Inspection Techniques, Addison-Wesley 1993
  4. C. Rupp, M. Recknagel, Messbare Qualität in Anforderungsdokumenten, in: OBJEKTspektrum 4/2006
  5. S. Chidamer, C. Kemerer, A Metrics Suite for object-oriented Design, in: IEEE Trans on SE, Vol. 20, Nr. 6, 1994
  6. F. Simon, O. Seng, T. Mohaupt, Code-Quality-Management, dpunkt.verlag 2006
  7. R. Martin, Clean Code – Refactoring, Patterns, Testen und Techniken für sauberen Code, MITB Verlag 2009
  8. R. Dumke, C. Ebert, J. Heidrich, C. Wille, Messung und Bewertung von Software, in: Informatikspektrum, Band 36, Nr. 6, 2013
  9. H. Sneed, M. Baumgartner, R. Seidl, Software in Zahlen, Hanser Verlag 2011
  10. P. Duval, S. Matyas, G. Glover, Continuous Integration, in: M. Fowler Signature Books, Addison-Wesley 2012