Bachelorarbeit, 2015
58 Seiten, Note: 1,7
1 Einleitung
1.1 Motivation
1.2 Ziele der Arbeit
1.3 Aufbau der Arbeit
2 Mutationstests
2.1 Kernhypothesen
2.1.1 Entstehung von Fehlern
2.1.2 Entdeckung von Fehlern
2.2 Vorgehen
3 Continuous-Integration
3.1 Grundprinzipien
3.2 Der Continuous-Integration-Prozess
4 Integration des Mutationstestwerkzeugs
4.1 Vorstellung der Testumgebung
4.1.1 Quality-Assurance-Extension
4.1.2 Confgurat on-Center-Client-Extension
4.1.3 Confgurat on-Center-Interface-Extension
4.1.4 Careerservice-Extension
4.1.5 Components-Extension
4.1.6 Attendeelist-Extension
4.1.7 Application-Editor-Extension
4.2 Auswahl des Mutationstestwerkzeugs
4.2.1 Anforderungen an das Mutationstestwerkzeug
4.2.2 Vorstellung des gewählten Mutationstestwerkzeug
4.3 Vorgehen bei der Integration
4.4 Anpassung des Buildskripts
5 Auswertung der Integration
5.1 Herausforderungen während der Integration
5.1.1 Anpassung an HISinOne
5.1.2 Ressourcenverbrauch
5.2 Auswertung der Mutationstests
5.2.1 Interpretation der Ergebnisse
5.2.2 Analyse der Laufzeiten
5.2.3 Mutation Score und Testüberdeckung
5.3 Methoden zur Testverbesserung
5.3.1 Conditionals Boundary Mutator
5.3.2 Negate Conditionals Mutator
5.3.3 Math Mutator
5.3.4 Increments Mutator
5.3.5 Invert Negatives Mutator
5.3.6 Return Values Mutator
5.3.7 Void Method Call Mutator
6 Fazit
Anhang
Eine Qualitätseigenschaft von Softwaretests ist die Fähigkeit, Fehler in der getesteten Software zu entdecken. Diese Eigenschaft kann durch die Anwendung von Mutations- tests ermittelt werden. Mutationstests bauen künstlich erzeugte Fehler in ein Pro- gramm ein und messen anschließend, wie viele dieser Fehler durch die vorhandenen Testfälle entdeckt werden. Der Mutationstestprozess lässt sich durch Mutationstest- werkzeuge automatisieren.
Um die Qualität der Testfälle nach jeder Änderung am Programm- oder Testcode zu überprüfen ist es sinnvoll, Mutationstests in einen Continuous-Integration-Prozess zu integrieren. Bei dieser Art der Softwareentwicklung werden Veränderungen am System kontinuierlich eingepfegt.
Diese Arbeit dokumentiert die Integration des Mutationstestwerkzeugs Pitest in den Continuous-Integration-Prozess der Software HISinOne. Dabei werden aufgetrete- ne Herausforderungen während der Integration betrachtet und Lösungsmöglichkeiten vorgestellt. Den Kern dieser Arbeit bildet die Auswertung der von Pitest erzeugten Er- gebnisse. Dabei wird die Frage beantwortet, wie sich die relativ hohen Ressourcenan- forderungen von Mutationstests mit einem Continuous-Integration-Prozess vereinbaren lassen. Außerdem wird erläutert, wie sich aus den gewonnen Ergebnissen der Mutati- onstests systematisch Maßnahmen zur Testverbesserung ableiten lassen.
Abbildung 1: Der Mutationstestprozess
Abbildung 2: Das V-Modell
Abbildung 3: Der Continuous-Integration-Prozess aus Entwicklersicht
Abbildung 4: Zusammensetzung der Quality-Assurance-Extension
Abbildung 5: Zusammensetzung der Confguration-Center-Client-Extension
Abbildung 6: Zusammensetzung der Confguration-Center-Interface-Extension
Abbildung 7: Zusammensetzung der Careerservice-Extension
Abbildung 8: Zusammensetzung der Components-Extension
Abbildung 9: Zusammensetzung der Attendeelist-Extension
Abbildung 10: Zusammensetzung der Application-Editor-Extension
Abbildung 11: Vorgehen bei der Integration von Pitest in den Buildprozess von HISinOne
Abbildung 12: Index der Pitest Mutationstestergebnisse
Abbildung 13: Pitest Mutationstestergebnisse pro Paket
Abbildung 14: Farbliche Hinterlegung der Mutationstestergebnisse der Javaklasse
Abbildung 15: Liste der erstellten Mutationen
Abbildung 16: LLOC der Javaklassen in Relation zu den erzeugten Mutanten
Abbildung 17: Laufzeiten von Pitest in Relation zu den LLOC der Javaklassen
Abbildung 18: Laufzeiten von Pitest in Relation zu den LLOC der JUnit-Tests
Abbildung 19: Laufzeiten von Pitest in Relation zu den LLOC der JUnit-Tests
Abbildung 20: Laufzeiten von Pitest mit inkrementeller Analyse in Relation zu den LLOC
Abbildung 21: Mutation Score und Ü berdeckungsmaße der Extensions
Tabelle 1: Mutations-Operatoren von Mothra
Tabelle 2: aor Mutationen in Fortran
Tabelle 3: Ä quivalente Mutation in Java
Tabelle 4: Anforderungen an das Mutationstestwerkzeug
Tabelle 5: Aufistung der verfügbaren Mutationstestwerkzeuge für Java
Tabelle 6: Mutations-Operatoren von Pitest
Tabelle 7: Auszug aus dem Buildskript der Attendeelist-Extension
Tabelle 8: Laufzeiten des Builds pro Extension in Minuten
Tabelle 9: Erzeugte Mutanten und Mutation Score pro Extension
Tabelle 10: Conditionals Boundary Mutationen von Pitest
Tabelle 11: Negate Conditionals Mutationen von Pitest
Tabelle 12: Math Mutationen von Pitest
Tabelle 13: Increments Mutationen von Pitest
Tabelle 14: Invert Negatives Mutationen von Pitest
Tabelle 15: Return Values Mutationen von Pitest
Tabelle 16: Void Method Call Mutationen von Pitest
Tabelle 17: Beispieljavaklasse zur Demonstration der Mutationstests
Tabelle 18: Beispieltestklasse zur Demonstration der Mutationstests
Tabelle 19: Beispielbuildskript zur Demonstration der Mutationstests
Diese Arbeit dokumentiert die Integration eines Mutationstestwerkzeugs in einen Continuous-Integration Prozess. Dabei werden aufgetretene Herausforderungen betrachtet und Lösungsmöglichkeiten aufgezeigt. Außerdem werden die Ergebnisse der Mutationstests diskutiert. Der Fokus der Diskussion liegt dabei auf der Vereinbarkeit von Mutationstests mit einem Continuous-Integration-Prozess und der systematischen Ableitung von Maßnahmen zur Testverbesserung.
Dieses Kapitel leitet die Fragestellung dieser Arbeit ein und bietet eine Übersicht über Zielsetzung und Aufbau der Arbeit. Dazu motiviert Abschnitt 1.1 die Anwendung von Mutationstests in einem Continuous-Integration-Prozess. Abschnitt 1.2 erläutert die Ziele der Arbeit und ordnet sie in den wissenschaftlichen Kontext ein. Abschnitt 1.3 beschreibt abschließend den Aufbau und die inhaltliche Zusammensetzung dieser Arbeit.
Softwaretests sind eine Möglichkeit, Fehler in einer Software zu entdecken. Je später ein Fehler entdeckt wird, desto höher sind die Kosten für seine Behebung [Boe79, S.1]. Daher ist es sinnvoll, Softwaretests nach jeder Änderung am System auszuführen. Ein geeignetes Vorgehen dafür ist Continuous-Integration. Bei dieser Art der Software-Ent- wicklung werden Änderungen kontinuierlich in das Gesamtsystem eingepfegt. Nach je- der Änderung wird das System durch automatisierte Softwaretests überprüft [FF06, S. 5f].
Durch Testen lässt sich allerdings nie die vollständige Abwesenheit von Fehlern nachweisen [Dij72, S. 6]. Daher ist es das Ziel von Softwaretests, die Anzahl der vor- handenen Fehler in dem getesteten Programm zu minimieren. Idealerweise geschieht dies möglichst ffi ient, da die vorhandenen Ressourcen in einem Softwareprojekt be- schränkt sind [DIN09]. Effizienz bedeutet in diesem Kontext, dass möglichst viele Feh- ler durch möglichst wenig Aufwand entdeckt werden. Testfälle, die zwar Ressourcen verbrauchen, aber keine Fehler entdecken, sind nutzlos. Ein Qualitätskriterium einer Testmenge ist demnach ihre Fähigkeit, Fehler in der getesteten Software zu entdecken. Je mehr Fehler durch eine vorhandene Testmenge entdeckt werden, desto besser ist die Testqualität.
Mutationstesten ist eine in den 1970er Jahren vorgestellte Methode, um die Entde- ckungsfähigkeit einer Testmenge zu bestimmen [DLS78]. Dazu werden künstlich gene- rierte Fehler in ein Programm eingefügt. Je mehr dieser Fehler von den vorhandenen Testfällen erkannt werden, desto besser ist die Entdeckungsfähigkeit der Testmenge. Der Mutationstestprozess lässt sich durch Mutationstestwerkzeuge automatisieren. Um eine kontinuierliche Überwachung der Testqualität zu gewährleisten, ist es daher sinn- voll, ein Mutationstestwerkzeug in einen Continuous-Integration-Prozess zu integrieren.
Ein Ziel dieser Bachelorarbeit ist die Integration eines geeigneten Mutationstestwerk- zeugs in den Continuous-Integration-Prozess von HISinOne. Dabei wird die Frage be- antwortet, wie sich die Eigenschaften eines Mutationstestwerkzeugs mit den Anforde- rungen eines Continuous-Integration-Prozesses eines großen Softwareprojektes verein- baren lassen.
Das Hauptziel dieser Arbeit ist die Analyse des Nutzens der Integration des Mutationstestwerkzeugs. Dazu werden die benötigten Ressourcen für die Integration und den Betrieb des Mutationstestwerkzeugs in Relation zu den erhaltenen Ergebnissen gesetzt. Außerdem wird die Frage beantwortet, wie sich anhand der Ergebnisse der Mutationstests systematisch Maßnahmen zur Testverbesserung ableiten lassen.
Es gibt bereits einige Veröfentlichungen, die sich mit der automatisierten Generie- rung von Testfällen unter Zuhilfenahme von Mutationstests beschäftigen, wie beispiels- weise [Of88], [OJP99], [BLJ+01] und [FZ10]. Auch die automatisierte Verbesserung von vorhandenen Testfällen wurde beispielsweise in [BFJ+02] und [XTH+09] betrach- tet. Le et al. haben allerdings in ihrer Veröfentlichung [LAG+14] festgestellt, dass die Verbesserung von vorhandenen Testfällen, insbesondere bei imperativen Programmier- sprachen, eine herausfordernde Aufgabe ist. Um zu verstehen, warum ein Fehler nicht von den vorhandenen Testfällen entdeckt wurde, sei ein tieferes Verständnis des fehler- haften Programmcodes und der vorhandenen Tests notwendig [LAG+14, S. 1f]. Daher geht es in dieser Arbeit explizit um das Verständnis der durch die Mutationstests gene- rierten Fehler und wie dieses Wissen von Entwicklern genutzt werden kann, um ihre Testfälle zu verbessern.
Dieser Abschnitt bietet eine Übersicht über den Aufbau dieser Arbeit. Dazu erfolgt eine schrittweise Vorstellung der einzelnen Kapitel. Hierbei wird für jedes Kapitel kurz erläutert, welche Inhalte behandelt werden und wie diese Inhalte zusammenhängen.
Kapitel 1 beinhaltet die Einleitung der Arbeit. Hier werden die Fragestellungen vorgestellt und das Thema motiviert. Zudem werden die Zielsetzungen vorgegeben und die inhaltliche Struktur der Arbeit dargelegt.
In Kapitel 2 werden die Grundlagen der Mutationstests eingeführt, welche zum Verständnis dieser Arbeit notwendig sind. Dabei wird insbesondere die Rolle der Mutationstestwerkzeuge näher erläutert.
In Kapitel 3 fndet eine Einführung in die Prinzipien und Vorgehensweisen der Continuous-Integration statt. Hierzu wird der Continuous-Integration-Prozess beschrieben und die Rolle von unterstützenden Werkzeugen näher beleuchtet.
Kapitel 4 beschäftigt sich mit der Integration des Mutationstestwerkzeugs in den Continuous-Integration-Prozess des Hochschul-Management-Systems HISinOne. In dem Kapitel wird zunächst das Zielsystem vorgestellt und darauf basierend ein geeignetes Mutationstestwerkzeug ausgewählt. Anschließend wird das Vorgehen bei der Integrati- on beschrieben.
In Kapitel 5 wird die Integration des Mutationstestwerkzeugs analysiert. Dabei werden aufgetretene Herausforderungen während der Integration betrachtet und Lösungsmöglichkeiten erläutert. Außerdem werden die Ergebnisse der Mutationstests diskutiert. Der Fokus der Diskussion liegt dabei auf der Vereinbarkeit von Mutationstests mit einem Continuous-Integration-Prozess und der systematischen Ableitung von Maßnahmen zur Testverbesserung.
In Kapitel 6 wird schließlich ein Fazit gezogen. Dazu wird die Erfüllung der Zielsetzung r f ktiert. Außerdem erfolgt eine kurze Zusammenfassung der in dieser Arbeit gewonnenen Ergebnisse. Weiterhin wird auf mögliche Perspektiven hinsichtlich weiterer Entwicklungen eingegangen.
Mutationstesten ist ein automatisierbares, fehlerbasiertes Testverfahren, welches zur Ermittlung der Entdeckungsfähigkeit einer Testmenge dient. Bei einem Mutationstest werden Veränderungen in ein Programm eingebaut, welche von den dazugehörigen Tests entdeckt werden müssen. Dieses Kapitel stellt die Grundlagen der Mutationstests vor, welche für das Verständnis dieser Arbeit notwendig sind. Dazu erfolgt in Ab- schnitt 2.1 eine Einführung in die Kernhypothesen des Mutationstestens. Abschnitt 2.2 beschreibt das Vorgehen beim Mutationstesten und geht insbesondere auf die Rolle der Mutationstestwerkzeuge ein.
Die nachfolgenden beiden Abschnitte erläutern die Kernhypothesen, welche die Grund- lage für die Anwendung von Mutationstests bilden. Zusammen mit der Vorstellung des Mutationstestverfahrens haben DeMillo et al. in [DLS78] zwei Kernhypothesen entwi- ckelt, um ihr Vorgehen zu begründen. Zum Einen entwickelten sie die Competent Pro- grammer Hypothesis, welche sich mit der Entstehung von Fehlern beim Programmieren beschäftigt. Zum Anderen haben sie den Coupling Effect beschrieben. Er beschreibt, wie vorhandene Fehler miteinander zusammenhängen und wie sich dies zur Entde- ckung von Fehlern nutzen lässt.
Dieser Abschnitt beschreibt die erste Kernhypothese der Mutationstests, welche sich mit der Entstehung von Fehlern beschäftigt. Mutationstests machen Aussagen über die Entdeckungsfähigkeit einer Testmenge. Um diese Eigenschaft der Testmenge möglichst realistisch beurteilen zu können, erzeugen Mutationstests Fehler, die realitätsnah sind [ABL05]. Realitätsnähe meint dabei, dass die künstlich erzeugten Fehler realen Programmierfehlern nahe kommen. Diese Realitätsnähe begründet sich durch die erste Kernhypothese der Mutationstests: Die Competent Programmer Hypothesis. Sie wurde von DeMillo et al. in [DLS78, S. 34] vorgestellt:
„ Programmers have one great advantage that is almost never exploited: they create programs that are close to being correct! “
Die Hypothese besagt, dass ein kompetenter Programmierer seinen Code so schreibt, dass er die Spez fka ion erfüllt. Er programmiert nicht völlig am Ziel vorbei, sondern ihm unterlaufen nur einfache Fehler bei der Umsetzung. Als einfache Fehler werden die Fehler bezeichnet, welche durch die Änderung eines einzelnen Syntaxelements korrigiert werden können [Of92 S. 2]. Diese Fehler werden beim Mutationstesten durch die Mutations-Operatoren repräsentiert. Ein Mutations-Operator legt fest, welche Art von Fehlern in das Programm eingefügt werden können.
Eine Auf stung der ersten formal d fn erten Mutations-Operatoren aus dem Jahr 1986 [KO91, S. 1] für die Programmiersprache Fortran fndet sich in Tabelle 1. Die Operatoren werden von dem Werkzeug Mothra verwendet, welches zur Zeit das älteste noch verfügbare Mutationstestwerkzeug ist1.Ein Mutations-Operator steht immer für eine Gruppe von Veränderungen des gleichen Typs. Die Veränderungen müssen syntaktisch korrekt sein und dürfen keinen negativen Einfuss auf die Kompilierbarkeit des Programms haben [OU01, S. 2].
Abbildung in dieser Leseprobe nicht enthalten
Tabelle 1: Mutations-Operatoren von Mothra nach [KO91, Table 1, S. 4].
Der Operator aor aus Tabelle 1 steht beispielsweise für Veränderungen an arithmeti- schen Operatoren. Das heißt im Falle von Mothra, jede arithmetische Operation wird jeweils durch alle anderen möglichen arithmetisch Operationen ersetzt [KO91, S. 27]. Tabelle 2 zeigt die Anwendung des aor Mutations-Operators anhand eines Beispiels. In der linken Spalte der Tabelle steht der Original Code mit der Anwendung einer Additi- on (). In der rechten Spalte der Tabelle werden durch den aor Operator 7 Mutationen erzeugt. Neben der ursprünglich verwendeten Addition entstehen so jeweils Anweisun- gen mit Subtraktion (), Multiplikation (), Division () und Potenzbildung ( ). Weiterhin wird jeweils nur der linke oder der rechte Operand zurückgegeben, sowie der Rest der Division. Die Auswirkungen der anderen Mutations-Operatoren aus Tabelle 1 werden in [KO91, S. 22ff] detailliert beschrieben.
Abbildung in dieser Leseprobe nicht enthalten
Tabelle 2: aor Mutationen in Fortran.
Neben der Competent Programmer Hypothesis existiert als zweite Kernhypothese der Mutationstests der Coupling Efect. Während die Competent Programmer Hypothesis eine Aussage über die Entstehung von Fehlern macht, beschäftigt sich der Coupling Effect mit der Entdeckung dieser Fehler. Der Coupling Efect wurde in [DLS78, S. 35] folgendermaßen d fn ert:
„ Test data that distinguishes all programs d fe ing from a correct one by only simple errors is so sensitive that it also implicitly distinguishes more complex errors. “
Der Coupling Efect besagt, dass eine Testmenge, welche einfache Fehler in einem Programm entdeckt, auch sehr wahrscheinlich komplexere Fehler entdecken würde. Komplexere Fehler sind dabei nach D fn tion von Ofutt in [Of92, S. 2] diejenigen, welche sich nur durch die Änderung von mehr als einem Syntaxelement beheben lassen. Äquivalent zu komplexen Fehlern gibt es dementsprechend auch komplexe Mutationen, diese werden als Mutationen höherer Ordnung bezeichnet. Einfache Mutationen, wie beispielsweise in Tabelle 2, heißen dementsprechend Mutationen erster Ord nung. Der Coupling Efect lässt sich nun bezogen auf die Anwendung von Mutationen folgendermaßen umformulieren [Of92, S. 2]:
„ Complex mutants are coupled to simple mutants in such a way that a test data set that detects all simple mutants in a program will detect a large percentage of the complex mutants. “
Diese Hypothese wird als Mutation Coupling Effect bezeichnet und wurde unter anderem von Ofutt in [Of92] empirisch untersucht und bestätigt. Auf Basis des Mutation Coupling Efects werden bei Mutationstests traditionell nur Mutationen erster Ordnung verwendet. Dies spart Ressourcen, da nicht zusätzlich auch noch komplexere Mutationen erzeugt und überprüft werden müssen. Allerdings gibt es auch Veröfentlichungen, die sich mit der Anwendung von Mutationen höherer Ordnung beschäftigen, wie beispielsweise [JH08] und [PPG08].
Dieser Abschnitt beschreibt das allgemeine Vorgehen während des Mutationstestprozesses. Dabei liegt der Fokus auf einer automatisierten Durchführung der Mutationstests durch ein Mutationstestwerkzeug. Diese Automatisierung ist unter anderem dann sinnvoll, wenn die Ausführung durch einen Menschen einen erheblichen Aufwand bedeuten würde oder es sich um häufg wiederholte Tätigkeiten handelt. An welcher Stelle des Mutationstestprozesses Mutationstestwerkzeuge zum Einsatz kommen, wird nachfolgend anhand von Abbildung 1 erklärt.
Zu Beginn des Mutationstestprozesses erfolgt die Eingabe einer Software s. Abhängig von den gewählten Mutations-Operatoren werden nun Veränderungen in die Software eingebaut. Hierzu wird jeweils eine neue Softwareversion erzeugt, in der genau eine Mutation vorhanden ist. Die mutierten Softwareversionen heißen Mutanten. Die Menge der erzeugten Mutanten wird in Abbildung 1 mit S' bezeichnet. Aufgrund dieses Prozessschritts werden Mutationstests auch zur Gruppe der divers f ierenden Testverfahren gezählt. Bei dieser Testart werden die Testergebnisse nicht mit den SollErgebnissen der Spez fka ion verglichen, sondern mit den Testergebnissen einer leicht abgewandelten Programmversion [Lig02, S. 180].
Wie bereits in Tabelle 2 gezeigt, können beispielsweise aus einer Zeile Programmco- de durch Anwendung eines Mutations-Operators sieben Mutationen entstehen. Abhän- gig von der Anzahl an gewählten Mutations-Operatoren erhöht sich diese Zahl noch. Die Mutanten-Erzeugung kann ffi ient durch ein Mutationstestwerkzeug ausgeführt werden, da die Mutationen den festen Regeln der Mutations-Operatoren folgen.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 1: Der Mutationstestprozess nach [OU01, S. 3, Fig. 1].
Nach der Erstellung der Mutantenmenge S' werden die zu s gehörenden Testfälle, bezeichnet mit T, eingegeben. Die Testmenge T wird anschließend auf s ausgeführt. Die Eingabe und Ausführung der Testfälle kann automatisiert ausgeführt werden. Mehr Informationen zu der automatisierten Testausführung fnden sich im nachfolgen- den Kapitel 3, da automatisierte Testausführung ein Standard in der Continuous-Inte- gration ist.
Schlagen Testfälle aus T fehl, müssen entweder die fehlschlagenden Testfälle aus T oder der fehlerhafte Teil von s korrigiert werden. Dies ist eine notwendige Bedingung für fehlerbasiertes Testen [Mor90]. Wenn alle Tests aus T erfolgreich durchlaufen, kann mit der Ausführung von T auf den Mutanten begonnen werden. Dazu werden für jeden lebenden Mutanten s' aus S' die Testfälle aus T ausgeführt. Ein Mutant s' ist lebendig, wenn keiner der ausgeführten Tests fehlschlägt. Schlägt mindestens ein Test fehl, gilt er als eliminiert. Auch dieser Schritt kann ffi ient durch ein Mutationstestwerkzeug ausgeführt werden.
Abbildung in dieser Leseprobe nicht enthalten
Tabelle 3: Ä quivalente Mutation in Java.
Ist ein Testorakel vorhanden, können die überlebenden Mutanten auf ä quivalente Mutationen untersucht werden. Eine äquivalente Mutation ist eine semantisch äquiva- lente Veränderung des Quellcodes. Ein Beispiel dafür zeigt Tabelle 3. In diesem Java Codebeispiel wurde der Vergleichsoperator in der original for-Schleife durch ein % ersetzt. Das bedeutet, die Abbruchbedingung ist in der original Version erreicht, wenn der Zähler den Wert erreicht. Dies gilt ebenso für die mutierte Version. Dadurch gibt jede Schleife die Zahlen von 0 bis 4 aus und terminiert dann. Das Programm ver- hält sich semantisch äquivalent.
Das Testorakel legt fest, unter welchen Bedingungen ein Test als erfolgreich gewertet wird. Es ist die Aufgabe des Testorakels äquivalente Mutanten auszusortieren. Das Testorakel muss dazu in der Lage sein, Mutanten zu erkennen, die keinen Fehler im Programm darstellen. Äquivalente Mutanten können nicht durch einen automatischen Testfall entdeckt werden [BA82]. Somit ist ein menschliches Testorakel notwendig, welches äquivalente Mutanten erkennen und aussortieren kann.
Am Ende des Mutationstestprozesses steht die Ausgabe des Mutation Score, abgekürzt mit MS. Er wurde zuerst von DeMillo im Jahre 1980 eingeführt [DeM80] und setzt sich wie folgt zusammen:
Abbildung in dieser Leseprobe nicht enthalten
Der aus dieser Formel errechnete Wert gibt an, wie hoch die Entdeckungsfähigkeit der getesteten Testfälle ist. Der MS berechnet sich aus der Anzahl an eliminierten Mu- tanten geteilt durch die Anzahl an nicht-äquivalenten Mutanten. Erfolgt keine Selekti- on der äquivalenten Mutanten, spricht man auch von einem Mutation Score Indikator [Mad07, S. 3], kurz MSI. Der MSI gibt nur die untere Grenze des MS an, da die An- zahl der äquivalenten Mutanten im Nenner des MS abgezogen wird. Die Berechnung des MS erfolgt durch das verwendete Mutationstestwerkzeug. Der berechnete MS kann dabei zwischen 0 und 1 liegen. Je höher der MS, desto höher ist die Qualität der Test- fälle aus T.
Continuous-Integration beschreibt ein spezielles Vorgehen bei der Software Entwicklung. Ziel dieses Vorgehens ist es, eine kontinuierliche Integration von Änderungen in das Gesamtsystem zu gewährleisten [FF06, S. 1]. In diesem Kapitel erfolgt eine Einführung in die Grundlagen der Continuous-Integration. In Abschnitt 3.1 werden die Grundbegr feundP inzipien der Continuous-Integration erläutert. In Abschnitt 3.2 erfolgt anschließend eine Vorstellung des Continuous-Integration-Prozesses. Dabei wird auch auf die Rolle der beteiligten Werkzeuge eingegangen.
In diesem Abschnitt werden die Grundprinzipien der Continuous-Integration näher er- läutert. Als erstes erfolgt die Erklärung notwendiger Grundbegr f Abbildung 2 illus- triert dafür einen Ausschnitt des V-Modells nach Boehm [Boe79, S. 4, Fig. 2]. Das V- Modell beschreibt die logischen Produkte einer Software. Der hier gezeigte Ausschnitt konzentriert sich auf die Entwicklung der Software, inklusive der Entwurfs- und Test- aktivitäten. Anhand der Abbildung wird deutlich, dass die Integration der Software alle Ebenen des V-Modells betr f Eine Ebene entspricht dabei der Granularität der logischen Produkte. Komponenten bilden die kleinsten logischen Einheiten. Werden die Komponenten miteinander verbunden, wächst ihre Größe. Das System bildet schließ- lich den Abschluss der Integration, da es alle Einheiten in sich vereint.
Der Zeitpunkt der Integration ist nicht vorgegeben. Man kann jede Komponente eines Systems separat entwickeln und erst nach Fertigstellung der Entwicklung die Komponenten zu einem Gesamtsystem zusammensetzen. Ziel der Continuous-Integration ist es aber, diese Integration möglichst frühzeitig auszuführen. Frühzeitig heißt dabei, nach jeder sign fkanten Änderung am System [DMG07, S. 4].
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 2: Das V-Modell nach [Boe79, S. 4, Fig. 2].
Das frühzeitige Integrieren beinhaltet auch das frühzeitige Testen. Frühzeitiges Tes- ten gewährleistet, dass Fehler so früh wie möglich entdeckt werden [FF06, S. 7]. Dies ist sinnvoll, da ein Fehler umso mehr Kosten verursacht, desto später er entdeckt wird [Boe79, S. 2, Fig. 1]. Umso früher ein Fehler entdeckt wird, umso weniger Aufwand ist für seine Behebung notwendig [FF06, S. 3]. Das gilt nicht nur für Programmierfehler, sondern auch für Fehlkommunikation. Werden Missverständnisse frühzeitig erkannt, können sie auch direkt behoben werden. So kann vermieden werden, dass Entwickler aneinander oder an der Spez fka ion vorbei programmieren. Das Aufdecken dieser Missverständnisse ist durch Continuous-Integration möglich, da beispielsweise Schnitt- stellenfehler frühzeitig entdeckt werden können. Dies geschieht, indem die Annahmen der Entwickler direkt validiert werden, sobald sie ihre Komponente in das Gesamtsys- tem integrieren.
Ein weiterer großer Vorteil der Continuous-Integration ist, dass jeder Projektteil- nehmer zu jedem Zeitpunkt weiß, was der aktuelle Stand des Projektes ist [FF06, S. 10]. Kein Entwickler programmiert monatelang alleine, sondern jeder teilt seinen Ent- wicklungsfortschritt so früh wie möglich mit allen anderen. Dies sorgt für eine Mini- mierung des Fehlschlagrisikos, da sich der Projektfortschritt jederzeit realistisch beur- teilen lässt [FF06, S. 11f]. Allerdings ist der Betrieb einer Continuous-Integration auch mit Aufwand verbunden, da zunächst eine passende Infrastruktur gesch f n werden muss. Weiterhin ist es für eine häufge Integration notwendig, die Dauer des Integrati- onsprozesses kurz zu halten [FF06, S. 8]. Das bezieht sich insbesondere auf die Laufzeit der Kompilierung und der Tests. Wie sich die Minimierung der Laufzeitdauer mithilfe von Werkzeugen bewerkstelligen lässt, wird im nachfolgenden Abschnitt erläutert.
Um das Vorgehen bei der Continuous-Integration besser verstehen zu können, be- schreibt dieser Abschnitt den Continuous-Integration-Prozess. Da sich diese Arbeit mit der Integration eines Mutationstestwerkzeugs in einen Continuous-Integration-Prozess beschäftigt, wird auch die Rolle der beteiligten Werkzeuge herausgearbeitet. Die ge- nannten Werkzeuge beschränken sich dabei auf Java-kompatible Beispiele, da auch das Anwendungsbeispiel dieser Arbeit in Java programmiert wurde. Dazu enthält die nach- folgende Abbildung 3 eine Darstellung des Continuous-Integration-Prozesses aus Ent- wicklersicht nach [FF06].
Das Fundament der Continuous-Integration ist das Versionskontrollsystem. Beispiele für Versionskontrollsysteme sind Subversion [SVN15], Git [Git15] oder Concur rent Versions System [CVS15]. Das Versionskontrollsystem bildet den zentralen Ort, an dem alle relevanten Elemente des Projektes gespeichert werden. Dazu gehören insbesondere der Programmcode und seine Abhängigkeiten. Dies ermöglicht es den Entwicklern, jederzeit eine Kopie des Gesamtsystems zu erstellen. Dazu wird eine lokale Kopie der Daten aus dem Versionskontrollsystem erstellt. Dieser Vorgang nennt sich Checkout und ist der Beginn des Prozesses aus Abbildung 3.
Nach dem Checkout der Software s kann der Entwickler Änderungen an seiner loka- len Kopie durchführen. Sind die Änderungen abgeschlossen, löst der Entwickler lokal einen Build von s aus. Dieser beinhaltet die Kompilierung der Software, aber auch das Ausführen von verschiedenen Tests [DMG07, S. 4]. Auch Quellcode Inspektionen und das Erzeugen einer Distribution kann Bestandteil des Builds sein. Der Build wird über ein Buildskript vollständig automatisiert, beispielsweise über Ant [Ant15]. Die während des Buildprozesses ausgeführten Tätigkeiten benötigen jeweils eigene Werkzeuge. Die Kompilierung übernimmt der Java Compiler, welcher über Ant aufgerufen werden kann. Automatisierte Tests können beispielsweise über JUnit [JUn15] ausgeführt wer- den. Inspektionen wie beispielsweise die Berechnung von Überdeckungsmaßen können durch Werkzeuge wie Cobertura [Cob15] oder JaCoCo [JaC15] durchgeführt werden. Das Erzeugen einer Distribution von Java Programmen kann recht einfach gehalten werden, indem über Ant eine ausführbare JAR Datei erzeugt und gespeichert wird.
Abbildung in dieser Leseprobe nicht enthalten
Abbildung 3: Der Continuous-Integration-Prozess aus Entwicklersicht nach [FF06].
Nachdem der Build von s abgeschlossen ist, gibt es zwei Möglichkeiten: Die erste Möglichkeit ist, dass während des Builds Fehler aufgetreten sind. Das können bei- spielsweise fehlschlagende Tests oder auch ein zu geringes Überdeckungsmaß sein. Die- se Fehler müssen zunächst korrigiert werden und der Build muss erneut gestartet wer- den. Die zweite Möglichkeit ist, dass der Build erfolgreich durchgelaufen ist. Dann kann mit dem nächsten Schritt aus Abbildung 3 fortgefahren werden, dem Merge. Bei einem Merge wird die lokale Version des Entwicklers mit der aktuellen Version des Versionskontrollsystems lokal zusammengeführt. Das ist notwendig, da in der Zwi- schenzeit auch andere Entwickler etwas am Gesamtsystem verändert haben können. Der Build muss nach dem Merge erneut ausgelöst werden, um die Kompatibilität der eigenen Änderungen zum aktualisierten Gesamtsystem zu gewährleisten. Auch hier müssen eventuell auftretende Fehler wieder korrigiert werden.
Der letzte Schritt des Continuous-Integration-Prozesses aus Entwicklersicht ist der Commit der lokal durchgeführten Änderungen. Der Commit geschieht erst, wenn lokal keine Fehler mehr gefunden werden und die Aktualität der lokalen Version von s durch einen oder mehrere Merges sichergestellt wurde. Bei einem Commit werden nun die lokalen Änderungen in das Versionskontrollsystem übertragen. Nach einem erfolgreichen Commit sind diese Änderungen in das Gesamtsystem integriert.
Damit ein Commit als erfolgreich gewertet wird, erfolgt erneut ein Build des Sys- tems. Der Build fndet mit der aktuell im Versionskontrollsystem enthaltenen Pro- grammversion statt. Dieser Vorgang kann durch einen Continuous-Integration-Server übernommen werden. Hierfür ist Jenkins [Jen15] ein populäres Beispiel aus der Open Source Community. Ein Continuous-Integration-Server kann automatisch einen Build auslösen, sobald eine Änderung commited wird. Weiterhin kann der Server den Commit auch eigenständig ablehnen, falls der Build fehlschlägt. Der Entwickler kann über diesen Fehlschlag beispielsweise per Mail informiert werden.
[...]
1 Stand: Juli 2015.
Der GRIN Verlag hat sich seit 1998 auf die Veröffentlichung akademischer eBooks und Bücher spezialisiert. Der GRIN Verlag steht damit als erstes Unternehmen für User Generated Quality Content. Die Verlagsseiten GRIN.com, Hausarbeiten.de und Diplomarbeiten24 bieten für Hochschullehrer, Absolventen und Studenten die ideale Plattform, wissenschaftliche Texte wie Hausarbeiten, Referate, Bachelorarbeiten, Masterarbeiten, Diplomarbeiten, Dissertationen und wissenschaftliche Aufsätze einem breiten Publikum zu präsentieren.
Kostenfreie Veröffentlichung: Hausarbeit, Bachelorarbeit, Diplomarbeit, Dissertation, Masterarbeit, Interpretation oder Referat jetzt veröffentlichen!
Kommentare