8. Testautomatisierung • • • • • • Was meint hier Automatisierung • klassische Testansätze – Entwicklung einer Testspezifikation (Vorbedingung, Ausführung, erwartete Ergebnisse) – manuelle Testausführung – manuelle Erfassung und Auswertung der Testergebnisse • erste Automatisierung – Werkzeuge wie JUnit, Marathon erlauben die automatische Testausführung und Protokollierung (teilweise Auswertung) – Werkzeuge müssen einzeln gestartet werden • zweite Automatisierung – mehrere Werkzeuge laufen nacheinander / zusammen – Ergebnisse werden zentral protokolliert Automatisierungsidee Beispiele für Werkzeuge Build-Server Idee von Build-Werkzeugen Einführung in Ant Tests aus Ant starten Software-Qualität Stephan Kleuker 257 Werkzeuge - Beispiele (1/3): Ant Stephan Kleuker Stephan Kleuker 258 Werkzeuge - Beispiele (2/3): Maven • Build-Prozess ist XML-Datei • Build-Prozess als Baumstruktur (project, target, task) • in Tasks steht, was mit welchem Werkzeug (Compiler, JUnit, ...) wo gemacht werden soll • für Java-Standardwerkzeuge sind Tasks bereits direkt in Ant enthalten • einige Werkzeuge bringen eigene Tasks zur Nutzung in Ant mit (TestNG) • Tasks selbst einfach in Java programmierbar • Ant liefert keinen Standard-Build-Prozess (selbst schreiben) • http://ant.apache.org/ Software-Qualität Software-Qualität 259 • alle Projekteigenschaften in zentraler Datei pom.xml • Project Object Model (mitgeliefert oder von Herstellern geliefert) • definiert Standard-Build-Prozess • Artefakt-Repository (Verwaltung von Jars) • Verwaltung der Projektabhängigkeiten (auch Beachtung abhängiger Versionsnummern, mit Nachlademöglichkeiten) • Build-Report als Website • einfach erweiterbar • deutlich mehr Einarbeitungsaufwand als Ant • dann deutlich einfacher nutz- und wartbar als Ant • http://maven.apache.org/ Software-Qualität Stephan Kleuker 260 Build-Server Werkzeuge - Beispiele (3/3): CruiseControl • Software-Erstellung und Testdurchführung kann eigenen Werkzeugen überlassen werden • Möglichkeit zur kontinuierlichen Integration • Führt Tests zu definierten Zeitpunkten aus; ermöglicht einfache Regressionstests (Wiederholung alter Testfälle) • Misst Testüberdeckung (kann mehrere Testwerkzeuge zusammen nutzen) • kann im Fehlerfall zuständige Personen benachrichtigen • erstellt im Erfolgsfall auslieferbares Artefakt ( -> ArtefaktRepository) • • • • • • • • CruiseControl configuration-Dateien in XML Stößt Ant-, Maven- oder Batch-Builds an kann andere Werkzeuge anstoßen (XCode) Konsole als Web-Anwendung Build-Log Meldet Build-Ergebnis über Email, rss gibt graphische Konfigurationswerkzeuge http://cruisecontrol.sourceforge.net/ • Alternativen: Apache Gump, Anthill, Hudson, Continuum, ... http://de.wikipedia.org/wiki/Kontinuierliche_Integration Software-Qualität Stephan Kleuker 261 Konzept von Ant (und make) Software-Qualität Stephan Kleuker Erinnerung an make • Es gibt zentrales Ziel (project) , was erreicht werden soll (z. B. vollständige Kompilation) • Jedes Ziel besteht aus Teilzielen (target), die vorher erreicht werden müssen (z. B. Übersetzung eines Teilpakets) • Werkzeug stellt Regeln auf, was in welcher Reihenfolge gemacht werden muss, um zentrales Ziel zu erreichen all : file1.o file2.o file3.o gcc -o prog file1.o file2.o file3.o • Werkzeug bietet dabei u. a. – Reaktionsmöglichkeiten bei Fehlern – Varianten bei der Ausführung – Möglichkeit, Ordner zu löschen und anzulegen, Dateien zu kopieren, verschieben und löschen file2.o : file2.c gcc -Wall -c file2.c Software-Qualität Stephan Kleuker 262 file1.o : file1.c gcc -Wall -c file1.c file3.o : file3.c gcc -Wall -c file3.c 263 Software-Qualität Stephan Kleuker 264 Beispiel für Abhängigkeiten <target <target <target <target Ant-Basisskript (erzeugt von Eclipse) name="init"/> name="preprocess" depends="init"/> name="compile" depends="init,preprocess"/> name="package" depends="compile"/> • Die Reihenfolge der Ziele (target) in der Datei hat keine Bedeutung, nur „depends“ dabei wichtig • Neben einem default-Ziel kann man beim Start ein Ziel auswählen, z. B. compile • alle depends betrachtet und schrittweise vom Werkzeug in mögliche Reihenfolge gebracht, hier: – init hat keine Abhängigkeiten, wird zuerst ausgeführt (was, hier nicht sichtbar) – preprocess benötigt init, da schon ausgeführt, wird nur preprocess ausgeführt Software-Qualität Stephan Kleuker 265 Skript-Konstanten (Eigenschaften, Properties) • Nutzung von Property-Werten mit ${eigen} <property name= "db" value = "${eigen}.db"/> • Bei Pfaden wird statt „value“ dann „location“ genutzt, dabei werden / und \ automatisch angepasst <property name="ziel" location="${p}/bla/fas"/> <property name="ziel" location="${p}\bla\fas"/> • Laufwerksbuchstaben, wie „C:“ sind verboten (möglichst mit relativen Pfaden arbeiten) • Es gibt vordefinierte Properties, z. B. ${user.home}, ${basedir} Stephan Kleuker Software-Qualität Stephan Kleuker 266 Properies in Hilfsdatei build.properties • <property name="eigen" value = "Wert" /> Software-Qualität <?xml version="1.0"?> <!-- ============================================= Projekt, Datum, Aufgabe Autor, ============================================= --> <project name="project" default="default"> <description> description </description> <!-- ================================= target: default ================================= --> <target name="default" depends="depends" description="--> description"> </target> <!-- - - - - - - - - - - - - - - - - target: depends - - - - - - - - - - - - - - - - - --> <target name="depends"> </target> </project> 267 # Properties für den JUnit-Testfall # Basis-Verzeichnisse src=${basedir}/src build=${basedir}/build lib=${basedir}/../../lib/fest-swing-1.2 report=${basedir}/report # Quell-Verzeichnisse src.junit=${src}/junit # Verzeichnisse für generierte Artefakte build.junit=${build}/junit • in build.xml: <property file="build.properties" /> Software-Qualität Stephan Kleuker 268 Hilfsmittel: Zeitstempel Umgang mit Files und Dateien • Einfachste Form: Task <tstamp/> , dann nutzbare Variablen: – DSTAMP: aktuelles Datum, Default-Format yyyymmdd – TSTAMP: aktuelle Uhrzeit, Default-Format hhmm – TODAY: aktuelles Datum als String • konfigurierbar über format-Property <target name="zeigeZeit"> <tstamp> <format property="TODAY" pattern="dd.MMMM.yyyy" locale="de,DE"/> </tstamp> <echo message="DSTAMP = ${DSTAMP}"/> <echo message="TSTAMP = ${TSTAMP}"/> <echo message="TODAY = ${TODAY}"/> </target> [echo] DSTAMP = 20070209 [echo] TSTAMP = 1234 [echo] TODAY = 09.Februar.2007 Software-Qualität Stephan Kleuker 269 Beispiel-target: Kompilieren • weitere Parameter können der Ant-Dokumentation entnommen werden (...\ant\docs\manual\index.html) • classpath nur nutzen, wenn weitere Pakete genutzt werden • echo hier als Spielerei • Übersetzung aller Klassen in Verzeichnis src und Unterverzeichnissen Stephan Kleuker <copy todir="archive"> <fileset dir="src"> <include name="*.java"/> </fileset> Software-Qualität Stephan Kleuker </copy> 270 Einbinden externer Bibliotheken <!-- classpath in der Form besser weglassen! --> <target name="compile" depends="start" description="kompiliere"> <javac srcdir="src" destdir="build" classpath="." debug="on"> </javac> <echo message="in compile"/> </target> Software-Qualität • <mkdir dir="${builddir}"/> – legt auch fehlende Unterverzeichnisse z. B. bei /dist/nase/simpel/billig an – übersprungen, falls Verzeichnis existiert • <delete dir="${builddir}"/> • <copy file="src/Hai.java" tofile="back/Hai.java"/> • <move file="src/Hai.java" tofile="back/Hai.java"/> • Pattern / Wildcards / reguläre Ausdrücke – * für beliebig viele Zeichen – ? für genau ein Zeichen – ** alle Unterverzeichnisse, z. B. **/*.java • häufig Property fileset zum Ein- und Ausschließen nutzbar 271 <path id="ExternalLibs"> <pathelement location="${lib}/junit-4.8.2.jar" /> <pathelement location="${lib}\extensions\junit\fest-swingjunit-4.5-1.2\fest-swing-junit-4.5-1.2.jar"/> <pathelement location="${lib}/lib/fest-assert-1.2.jar" /> <pathelement location="${lib}/fest-mocks-1.0.jar" /> <pathelement location="${lib}/lib/fest-reflect-1.2.jar" /> <pathelement location="${lib}/fest-swing-1.2.jar" /> <pathelement location="${lib}/lib/fest-util-1.1.2.jar" /> </path> <target name="compile" description="Sourcen kompilieren"> <javac srcdir="${src}" destdir="${build}"> <classpath refid="ExternalLibs" /> </javac> </target> Software-Qualität Stephan Kleuker 272 Beispiel-target: Packen Beispiel-target: JUnit ausführen <target name="test" depends="compile" description="JUnit-Test ausführen"> <junit printsummary="on" fork="yes"> <!-- classpath für die Ausführung setzen --> <classpath> <pathelement location="${build}" /> <path refid="ExternalLibs" /> </classpath> <test name=„klicker.klickerTest" todir="${report}"> <formatter type="plain" usefile="true" /> </test> </junit> </target> <!-- existierendes Manifest mit Attribut file="" --> <target name="pack" depends="compile" description="packe"> <jar destfile="dist/gepackt.jar" basedir="build"> <manifest> <attribute name="Main-class" value="de.kleuker.XStarter"> </attribute> </manifest> </jar> <echo message="in pack"/> </target> • hier wird Manifest-Datei direkt erzeugt, zu nutzende Datei kann auch angegeben werden Software-Qualität Stephan Kleuker 273 test-Task starten Software-Qualität Software-Qualität Stephan Kleuker 274 Beispiel: Protokoll und Ergebnis Stephan Kleuker 275 Software-Qualität Stephan Kleuker 276 9. Metriken • • • • • • Nutzung von Maßsystemen • bisherigen Prüfverfahren sind aufwändig, besteht Wunsch, schneller zu Qualitätsaussagen zu kommen • Ansatz: Nutzung von Maßsystemen, die Zahlenwerte generieren, deren Werte Indiz für Qualität der SW sind • Werden Maße automatisch berechnet, kann man Qualitätsforderungen stellen, dass bestimmte Maßzahlen in bestimmten Bereichen liegen • Wichtig ist, dass man weiß, dass nur Indikatoren betrachtet werden, d.h. gewonnene Aussagen müssen nachgeprüft werden Idee von Maßsystemen Halstead live Variables Variablenspanne McCabe-Zahl LCOM* • Ähnliche Ansätze in der Projektverfolgung und Analyse der Firmengesamtlage (-> Balanced Scorecard) -> siehe Qualitätsmanagement Software-Qualität Stephan Kleuker 277 Metriken zur Ermittlung des Projektstands Software-Qualität Pakete Stephan Kleuker C1-Überdeckung C2-Überdeckung 278 • Lines of Code pro Methode (LOC) mögliche Grundregel: maximale Zahl unter 20 • Methoden pro Klasse Die Zahl sollte zwischen 3 und 15 liegen • Parameter pro Methode Die Zahl sollte unter 6 liegen • Exemplarvariablen pro Klasse Die Zahl sollte unter 10 liegen [Entitäten ?] • Abhängigkeiten zwischen Klassen Keine Klasse sollte von mehr als vier Klassen abhängen • weitere Maßzahlen z. B. Anzahl von Klassenvariablen und Klassenmethoden 50% Use Cases Stephan Kleuker Grobe Metriken (Min, Max, Schnitt, Abweichung) programmiert/ überdeckt 100% 0% Software-Qualität 279 Software-Qualität Stephan Kleuker 280 Halstead-Maße (1/2) Halstead-Maße (2/2) Basiert auf vier Größen • N1: Gesamtzahl der verwendeten Operatoren (in Java z.B. +,-,*,/,==,if,while,<Methodenname>) • N2: Gesamtzahl der verwendeten Operanden (Variablen, Konstante) • n1: Anzahl der genutzten unterschiedlichen Operatoren • n2: Anzahl der genutzten unterschiedlichen Operanden • Größe des Vokabulars: n=n1+n2 • Länge der Implementation: N=N1+N2 if (k<2){ if (k>0) x=x*k; } Software-Qualität unterschiedliche Operatoren: if ( < ) { > = * ; } unterschiedliche Operanden: k 2 0 x N1 = 13 N2 = 7 n1 = 10 n2 = 4 Stephan Kleuker 281 Live Variables Software-Qualität Stephan Kleuker 282 Variablenspanne • Ansatz: Erstellung/Prüfung einer Anweisung umso schwieriger, je mehr Variablen beachtet werden müssen • Eine Variable heißt zwischen der ersten und der letzten Nutzung lebendig • Für Variable x: maximaler Abstand (in Code-Zeilen) zwischen ihren Nutzungen. (Zeilennummer in der x zum (i+1)-ten Mal minus Zeilennummer in der x zum i-ten Mal vorkommt.) public static int mach(boolean a, boolean b){ //1 int x=0; //2 if (a) //3 x=2; //4 else a: 3-1=2 x=3; //5 b: 6-1=5 if (b) //6 x: 4-2=7-5=2 return(6/(x-3)); //7 else Maximum: 5 return(6/(x-2)); //8 Durchschnitt: 3 } public static int mach(boolean a, boolean b){ int x=0; // a,b,x lebendig if (a) // a,b,x lebendig x=2; // b,x lebendig else x=3; // b,x lebendig if (b) // b,x lebendig return(6/(x-3)); // x lebendig else return(6/(x-2)); // x lebendig } • Interessant sind maximale und mittlere Zahl (Gesamtzahl lebendiger Variablen durch Anzahl ausführbarer Anweisungen) lebendiger Variablen Software-Qualität Berechnung von D (Schwierigkeiten ein Programm zu schreiben oder zu verstehen) n1 * N2 D = ------------------2 * n2 • D ist Funktion vom Vokabular und der Anzahl der Operanden • Quotient N2 / n2 gibt die durchschnittliche Verwendung von Operanden an • Satz von Halstead: D beschreibt den Aufwand – zum Schreiben von Programmen, – den Aufwand bei Code- Reviews und – das Verstehen von Programmen bei Wartungsvorgängen. Anmerkung: Aufbauend auf den Basismetriken gibt es weitere Metriken, die unterschiedliche Eigenschaften eines Programms erfassen Stephan Kleuker • Wieder durchschnittlicher und maximaler Wert interessant 283 Software-Qualität Stephan Kleuker 284 Zyklomatische Zahl nach McCabe Beispiele für die zyklomatische Zahl 1. Man konstruiere die Kontrollflussgraphen 2. Man messe die strukturellen Komplexität Die zyklomatische Zahl z(G) eines Kontrollflussgraphen G ist: z(G) = e – n + 2 mit e = Anzahl der Kanten des Kontrollflussgraphen n = Anzahl der Knoten Anzahl Kanten Anzahl Knoten McCabe Zahl Zyklomatische Komplexität gibt Obergrenze für die Testfallanzahl für den Zweigüberdeckungstest an In der Literatur wird 10 oft als maximal vertretbarer Wert genommen (für OO-Programme geringer, z. B. 5) für Java: #if + #do + #while + #switch-cases+ 1 Software-Qualität Stephan Kleuker 285 Erweiterte McCabe-Zahl 0 2 4 3 6 1 3 4 3 5 1 1 2 2 3 Software-Qualität Stephan Kleuker 286 Lack of Cohesion in Methods (LCOM*) - Ansatz • Komplexität von Verzweigungen berücksichtigen • gezählt werden alle Booleschen Bedingungen in if(<Bedingung>) und while(<Bedingung>): anzahlBedingung • gezählt werden alle Vorkommen von atomaren Prädikaten: anzahlAtome z. B.: ( a || x>3) && y<4 dann anzahlAtome=3 • erweitere McCabe-Zahl ez(G) = z(G) + anZahlAtome - anzahlBedingung • Frage: Gibt es Maß für gute Objektorientierung? • Ansatz (Indikator): Exemplarvariablen sollten in mehreren Methoden genutzt, möglichst kombiniert sein • Hinweis: Es muss vorher festgelegt werden, ob Klassenvariablen und Klassenmethoden berücksichtigt werden sollen • Was passiert, wenn man konsequent exzessiv OO macht und auch in den Exemplarmethoden get() und set() Methoden nutzt? Wie ist LCOM* dann rettbar? • wenn nur atomare Bedingungen, z. B. if( x>4), dann gilt ez(G) = z(G) Software-Qualität Stephan Kleuker 287 Software-Qualität Stephan Kleuker 288 Lack of Cohesion in Methods (LCOM*) - Berechnung LCOM*-Beispiel public class LCOMSpielerei { LCOM* = (avgNutzt–m) /(1-m) • nutzt(a) die Zahl der Methoden, die eine Exemplarvariable a der untersuchten Klasse nutzen • sei avgNutzt der Durchschnitt aller Werte für alle Exemplarvariablen • sei m die Anzahl aller Methoden der untersuchten Klasse • Ist der Wert nahe Null, handelt es sich um eine eng zusammenhängende Klasse • Ist der Wert nahe 1, ist die Klasse schwach zusammenhängend, man sollte über eine Aufspaltung nachdenken private int a; private int b; private int c; public void mach1(int x){ a=a+x; } public void mach2(int x){ a=a+x; b=b-x; } public void mach3(int x){ a=a+x; b=b-x; für Eclipse gibt es Plugin Metrics c=c+x; http://sourceforge.net/projects/metrics/ } berechnet u. A. erweiterte MCCabe-Zahl und LCOM* } Software-Qualität Stephan Kleuker 289 Beispiel eines Kivat-Diagramms Maßzahlen können graphisch dargestellt werden, im KivatDiagramm steht jede LOC Achse für eine Metrik, der weiße Bereich ist ok, die anderen Bereiche kritisch Variablenspanne Live Variables Software-Qualität Stephan Kleuker nutzt(a)=3 nutzt(b)=2 nutzt(c)=1 avgNutzt=6/3=2 LCOM*= (2-3) /(1-3) = -1/-2= 0.5 LCOM* zyklomatische Zahl 291 Software-Qualität Stephan Kleuker 290