Grundsätzliche Vorgehensweise bei automatisierten Softwaretests am Beispiel von JUnit und Bedeutung dieser für Continuous Integration
Aus Winfwiki
| Name des Autors / der Autoren: | Daniel Brodka |
| Titel der Arbeit: | Grundsätzliche Vorgehensweise bei automatisierten Softwaretests am Beispiel von JUnit und Bedeutung dieser für Continuous Integration |
| Hochschule und Studienort: | FOM Duisburg |
| Studiengang: | Bachelor of Science / Wirtschaftsinformatik, 3. Fachsemester |
| Name des Betreuers: | Dipl-Inf. (FH) Christian Schäfer |
| Erstellungszeitraum: | WS2009 / WS2010 |
| Abgabedatum: | 14.01.2009 |
Inhaltsverzeichnis |
1 Einleitung / Motivation
Aufgrund von immer komplexer werdenden Geschäftsprozessen im Unternehmensalltag steigen die Anforderungen an eine gute Software stetig.
Businesssoftware stellt die Geschäftsprozesse eines Unternehmens dar und optimiert diese. Aufgrund dieses Umstands steigt auch die Komplexität von Anwendungsprogrammen und die Schwierigkeit der Fehlererkennung erhöht sich überproportional (z.B. durch Seiteneffekte).
Anhand Abbildung 1 ist zu erkennen, dass in der Softwareentwicklung die meisten Fehler im Entwurf und der Realisierung entstehen (rote Balken). Jedoch wird nur ein Bruchteil dieser Fehler in der gleichen Phase erkannt (blaue Balken). Hierdurch ergibt sich die Problemstellung, dass wenn der Fehler in den späteren Phasen erkannt wird, höhere Kosten entstehen. Diese Kosten sind u.a. durch folgende Umstände zu begründen:
- Die Entwickler müssen sich aufgrund des Zeitverzugs erneut in die fachliche Thematik einarbeiten
- Je früher der Fehler im Softwarezyklus (Analyse, Entwurf, Realisierung, Einsatz, Wartung)[1] gemacht worden ist, umso mehr muss aufgearbeitet werden, da u.U. weitere Programmfunktionen auf den fehlerhaften Methoden basieren.
- Die Tests müssen ab der Phase, in der der Fehler entstanden ist, wiederholt werden.
Aufgrund dieser Umstände steigen die Fehlerkorrekturkosten nach der Realisierung erheblich an (siehe Abbildung 2).
Der sogenannte Worst - Case wäre in diesem Kontext, dass z.B. ein fehlerbehaftetes Softwareprodukt bei Kunden eingesetzt wird, woraufhin es zu Datenverlusten bei diesem Kunden kommt. Die daraus resultierenden Kosten wären hierbei nicht nur die Fehlerbehebung, die einen Rücksprung bis in die Analyse- oder Designphase des Produkts bedeuten könnte, sondern auch das geschädigte Image des Produkts und die Regresskosten bzw. Schadensersatzforderungen der betroffenen Unternehmen, soweit dies rechtlich möglich ist.
Um dem entgegenzuwirken, gibt es Möglichkeiten einen Großteil der durchzuführenden Tests sowohl auf der Code- als auch auf der funktionalen Ebene zu automatisieren.
Abgesehen von der Qualität des Softwareprodukts und dem damit einhergehenden steigendem oder fallendem Image einer Softwareschmiede können dadurch die Effizienz der Softwareentwicklung gesteigert und Kosten gespart werden.
2 Zielsetzung
Die vorliegende Arbeit befasst sich damit, welche Eigenschaften eine "gute" Software haben muss und wie dies in der heutigen Zeit realisiert werden kann. Hierbei ist die Thematik der AT (automatisierten Tests) um die Produkte qualitativ hochwertiger erstellen zu können im Fokus. Das Prinzip der AT wird abstrakt am Beispiel von JUnit (Framework in Java) beschrieben, kann jedoch auch leicht auf andere Frameworks bzw. andere Entwicklungssprachen übertragen werden.
Die darüberhinaus existierende Fragestellung, was CI (Continuous Integration) genau ausmacht und welche Beziehung zu JUnit hierbei besteht, wird ebenfalls erläutert.
3 Begriffsdefinition
3.1 Qualitätskriterien Software
Es gibt zwei generelle Perspektiven aus denen die Qualität eines Softwareprodukts beurteilt werden. Zum Einen ist dies die Sicht des Anwenders, der eine u.a. möglichst intuitiv – bedienbare, performante und zuverlässige Anwendung haben möchte.
Zum Anderen ist es die Sicht des Entwicklers, die eine geringfügig andere ist. Der Fokus liegt zuerst auf der technischen Vorgehensweise, der Verwendung von effizienten Techniken und Vorgehensmodellen, aber es gibt ebenso Schnittmengen wie z.B. die Performanz.
Ein gutes und ausgereiftes Produkt erfüllt die Anforderungen beider Perspektiven. Dies gilt ebenfalls für die Softwareentwicklung, die nicht nur den technischen Aspekt berücksichtigen darf. Folgende Kriterien umschreiben die Qualität eines Softwareproduktes und basieren auf der Norm DIN ISO 9126[2]. Ergänzend werden Teilmerkmale und die Begrifflichkeiten der Skalierbarkeit und der Verfügbarkeit hinzugefügt:
Tabelle 1: Qualitätskriterien von Software
| Kriterium | Beschreibung |
| Zuverlässigkeit (reliability) | Die Zuverlässigkeit zeichnet sich durch die Merkmale Reife, Fehlertoleranz und Wiederherstellbarkeit aus.
|
| Funktionalität (functionality) | Unter Funktionalität ist die Existenz und die Arbeitsweise der Funktionen, wie sie beschrieben und definiert worden sind, zu verstehen. Diese Umschreibung kann über folgende Teilmerkmale spezifiziert werden:
|
| Benutzbarkeit (usability) | Die Benutzbarkeit wird anhand der Verständlichkeit, Erlernbarkeit, Bedienbarkeit und Handlungsflexibilität definiert.
|
| Effizienz (efficiency) | Unter einer effizienten Anwendung ist zu verstehen, dass diese in Abhängigkeit zu ihrer Aufgabe nur die Ressourcen verwendet, die sie zum Zeitpunkt der Ausführung benötigt um das gewünschte Ergebnis zu erreichen.
|
| Änderbarkeit (modifyability) | Eine gute Änderbarkeit einer Anwendung bedeutet, dass diese mit möglichst geringem Aufwand verändert werden kann. Dieses Kriterium wird durch die Vorgehensweise der Testautomatisierung am meisten verbessert. Teilmerkmale sind hierbei die Analysierbarkeit, Modifizierbarkeit, Stabilität und Prüfbarkeit.
|
| Portabilität (portability) | Die Portabilität beschreibt wie leicht eine Anwendung auf ein anderes System bzw. auf eine andere Umgebung übertragen werden kann. Im Kontext von Java ist hier die sogenannte Plattformunabhängigkeit, die bedingt durch eine virtuelle Maschine und somit eine virtuelle Umgebung ist, zu nennen. Im Detail sind hierbei Anpassbarkeit, Installierbarkeit, Konformität und Austauschbarkeit zu betrachten.
|
| Skalierbarkeit | Die Skalierbarkeit beschreibt die Möglichkeit ein System an die Umgebung bezüglich ihrer Ressourcen anzupassen. Beispielsweise ist hier die Anzahl der Anwender / Lizenzen zu nennen, die ebenfalls Auswirkungen auf die zu verarbeitenden Datenmengen haben. |
| Verfügbarkeit | Das Kriterium der Verfügbarkeit ist eng verbunden mit der Zuverlässigkeit. Hierbei wird bewertet, wie hoch die Ausfallsicherheit oder aber der Aufwand im Fehlerfall zur Systemwiederherstellung ist. |
In Anlehnung an: Lassmann (2006) S. 154f
In einem gewissen Maß stehen diese Qualitätskriterien in einem Widerspruch zueinander, da z.B. eine aus Performanzgründen durchgeführte Anpassung ans Betriebssystem der Portabilität etc. widersprechen kann. Hierbei müssen die Kriterien dann den Anforderungen entsprechend gewichtet werden.
3.2 Test
Ein Test im Generellen besteht aus der Definition eines Soll - Zustands und dem Ist - Zustand. Bei der Durchführung eines Tests werden die Ist - Ergebnisse mit den erwarteten Ergebnissen (Soll) abgeglichen.
Tests werden begrifflich in Testebenen und Testverfahren kategorisiert, wobei die Testebene den Umfang des Tests beschreibt und das Verfahren die detaillierte Vorgehensweise definiert.
3.2.1 Testebenen
Der Begriff der Testebene beschreibt den Umfang des Testbereichs. Hierbei sind in der Literatur unterschiedliche Definitionen zu finden. Dennoch kann man anhand der Begrifflichkeit einordnen, welche artverwandt oder sogar identische Begriffe darstellen. Diese unter den folgenden Erläuterungen zusammengefasst:
Tabelle 2: Definition Testebenen
| Testebene | Verwandte Begriffe | Beschreibung |
| Komponententest | Unit - Test, Modultest, Entwicklertest | Diese Tests dienen der Absicherung der korrekten Funktionsweise von Systemteilen (Klassen, Module, Subsysteme etc.)[3]. Hierbei ist aber auch zu berücksichtigen, dass ein Unit - Test auf der kleinsten vorkommenden Ebene, wie z.B. einer Funktion oder Methode durchgeführt werden kann. |
| Integrationstest | Verbundstest, (Regressionstest) | Mehrere Module oder Klassen werden zusammen getestet, woraufhin das korrekte Zusammenspiel aller (bereits vorhandenen) Systemteile überprüft wird[4]. Der Regressionstest kann ebenfalls in diese Definition fallen, allerdings wird diese Definition nur verwendet, wenn Änderungen oder Ergänzungen am Quellcode durchgeführt wurden. |
| Systemtest | Dieser Test stellt eine Überprüfung des kompletten Softwaresystems dar. Auf Basis der zuvor festgelegten Anforderungsdokumente wird geprüft, ob die Kriterien für die Bereiche Funktion, Leistung und Qualität erfüllt werden[5]. Folgende Tests werden im Detail durchgeführt:
| |
| Abnahmetest | Dieser Test ist dem Systemtest ähnlich, allerdings wird dieser auf der Zielumgebung (z.B. beim Kunden vor Ort) statt auf einer Entwicklungsumgebung durchgeführt. |
3.2.2 Teststrategien
Es gibt drei generelle Verfahrensweisen bei Softwaretests. Hierunter fallen der White – Box – Test, der Black – Box – Test und der Gray - Box - Test.
Der White – Box – Test stellt einen Strukturtest dar und ist ebenfalls unter dem Begriff Glass - Box - Test bekannt[8]. Da dieser Test auf Quellcodeebene durchgeführt wird sind alle Datenstrukturen und die generellen Abläufe bekannt und nachvollziehbar. Im Javaumfeld sind u.a. die Tools bzw. Frameworks
im Gebrauch.
Diese werden mittels Regeln (über 700 Regeln derzeit vorhanden) konfiguriert und können einzeln, aber auch im Verbund, eingesetzt werden. Beispiele für Fehler, die diese Tools erkennen können, sind folgende:
- Endlosrekursion
- Fehlende Dokumentation der Methoden und Klassen
- Codeduplikate (widerspricht dem Prinzip der Modularisierung)
- Verstöße gegen Formatierungskonventionen (verschlechtert Wartung/Erweiterung von Softwareprogrammen)
- Verstöße gegen Namenskonventionen
- Null – Pointer
- nicht geschlossene Streams / Dateizugriffe
Der Black – Box – Test ist ein Funktionstest. Die Anwendung oder ein Teil dieser wird mit Daten aufgerufen und das Ergebnis wird überprüft. Der Name beschreibt somit das Verfahren. Entgegen dem White – Box – Test wird nicht geprüft, wie das Ergebnis ermittelt wird, sondern nur, ob es korrekt ist. Da dieser Test immer zur Laufzeit durchgeführt wird, wird hier ebenfalls von einem dynamischen Test gesprochen. Zumindest beim manuellen Testen ist diese Teststrategie nur für Programme mit einer kleinen Zahl von Eingabemöglichkeiten geeignet[9].
Der Gray - Box - Test stellt eine Mischung aus White - Box und Black - Box dar. Ein Teil der internen Strukturen ist bekannt, aber nicht alle, wie beim White - Box - Test. Ein Unit - Test könnte man ebenfalls als Gray - Box - Test bezeichnen, da der Test primär aus fachlicher Sicht erstellt wird, allerdings Strukturen ebenfalls bekannt sind. Im Laufe der iterativen Entwicklung jedoch können sich die Strukturen bedingt ändern.
4 Automatisiertes Testen
4.1 Testgetriebene Entwicklung
Die testgetriebene Entwicklung oder auch TDD (Test – Driven – Development) beschreibt eine agile Vorgehensweise bei der Softwareentwicklung, die so tiefgreifend ist, dass hierbei ebenfalls von einem Entwurfsparadigma gesprochen werden kann. Diese Vorgehensweise ist ebenfalls unter dem Begriff Test – First Programming bekannt, da eine der Vorraussetzungen ist, dass Unit – Tests zuvor implementiert werden[10].
Vor der eigentlichen Erstellung des Programmquellcodes werden die Tests der zukünftigen Programmteile programmiert. Dies bewirkt, dass sofort bei der Programmierung ebenfalls die fachliche Sicht berücksichtigt wird. Hierdurch wird die Programmqualität schon im Vorhinein verbessert, da die Entwickler sich die fachlichen Anforderungen ebenfalls bewusst machen. Des Weiteren besteht die Möglichkeit durch das Vorhandensein der programmierten Testfälle Tests zu wiederholen, was sogleich die Basis für eine Testautomatisierung darstellt.
Der Begriff der Agilität rührt hierbei daher, dass der Entwickler flexibel auf neue Produktanforderungen reagieren kann. Weitere Entwicklungsstrategien, die ebenfalls das Prinzip TDD beinhalten, sind XP (Extreme Programming) und Pair Programming. Gerade bei den häufig wechselnden Anforderungen kann durch das Prinzip der testgetriebenen Entwicklung eine Vielzahl von Seiteneffekten durch die Änderungen frühzeitig entdeckt und somit korrigiert werden.
4.2 Unit - Tests
Unter einer Unit, also einer Einheit ist abstrakt ein abgeschlossener Teil eines Programmcodes zu verstehen. Ob die Unit nun durch fachliche Zusammenhänge oder durch die Programmstruktur definiert ist, liegt in der Entscheidung des Softwareentwicklers.
Bei einer guten Modularisierung stellt eine Methode / Funktion gleichzeitig auch einen fachlichen Teilbereich dar (z.B. Berechnung einer Summe). Für diesen abgeschlossenen Teil werden ein oder mehrere Tests definiert, die bei Bedarf aufgerufen werden können. Die meisten der Unit - Tests bestehen aus den folgenden drei Schritten:
- Spezifikation der Testdaten
- Aufruf des Testlings (dem zu testenden Bereich)
- Vergleich der Soll- und Istwerte[11]
4.2.1 Unit - Test - Frameworks
Für fast alle objektorientierten und teilweise auch prozeduralen Programmiersprachen sind inzwischen Frameworks vorhanden, die Unit – Test ermöglichen.
Einige Frameworks zu den geläufigsten Sprachen sind hierbei folgende:
Tabelle 3: Frameworks von Unit - Tests
| Programmiersprache | Framework |
| C | CUnit |
| C++ | CppUnit |
| C# | csUnit |
| Java | JUnit |
| .NET(C, C++, C#, VB.NET) | NUnit |
4.2.2 Beschreibung einer möglichen Entwicklungsumgebung
Um die Techniken der AT anzuwenden und alle Vorteile von CI nutzen zu können, muss eine Infrastruktur dafür geschaffen werden. Ein Beispiel hierfür stellt das gezeigte Schaubild dar. Diese Systemkonfiguration ermöglicht es einem Entwicklungsteam gleichzeitig an einem Projekt zu arbeiten, die Änderungen automatisch zu testen und einen aktualisierten Programmstand zu erstellen.
Die hier beschriebenen Produkte sind durch ähnliche austauschbar, jedoch ist zu beachten, welches Produkt welche Funktionen übernimmt. Ausgehend von einem einzelnen Entwicklungsplatz (Client) kann das System wie folgt beschrieben werden:
- Der Entwickler erstellt neue Programmteile oder ändert vorhandene. Diese legt er nach Fertigstellung in dem Softwareversionssystem ab.
- Das Softwareversionssystem hat u.a. die Aufgabe die Daten zentral zu verwalten und eine Historie der Änderungen zu pflegen. Des Weiteren werden Dateien, die von einem Entwickler bearbeitet werden, entsprechend markiert. Sollten zwei Entwickler eine Datei verändern und es dabei zu einer zeitlichen Überschneidung kommen, würde das System dies ebenfalls den Entwicklern melden. Es ist nicht zwingend notwendig, dass das Softwareversionssystem auf dem gleichen Server, wie der Applikationsserver liegt.
- Der Applikationsserver stellt die Funktionalität Anwendungen verwalten und auch starten zu können (Hudson ist ein Javaprogramm in Form einer *.jar - Datei) bereit.
- Der Hudson ist der Continuous Integration Server. Die Aufgabe des CIS besteht darin die Plattform für ein automatisiertes Testen bereitzustellen, die Ergebnisse eines Testlaufs auszuwerten und in Form von Berichten darzustellen. Auch wird aus dem Hudson nach dem Erkennen von Programmänderungen im Softwareversionssystem das Build - Tool (hier: Maven) aufgerufen.
- Die Aufgabe von Maven ist hierbei die umfangreichste. Anhand eines definierten POM (Project Object Model)[12] wird das geänderte Projekt inklusive aller seiner Abhängigkeiten neu erstellt, die automatischen Tests durchgeführt und die Ergebnisse in Form einer XML - Datei zusammengefasst. Diese Ergebnisdatei wiederum wird vom Hudson interpretiert. Eine weitere Aufgabe von Maven ist die Aktualisierung der im Projekt verwendeten Bibliotheken. Je nach Einstellung wird automatisch eine aktuelle Version der Bibliotheken vor dem Build aus dem Internet geladen, ebenfalls ist ein Zugriff auf eine Quelle im Netzwerk möglich (Stichwort: Factoring). Darüberhinaus ruft Maven die schon genannten Testtools PMD, FindBugs und Checkstyle auf, wenn dies so in dem POM definiert ist.
Maven wird ebenfalls auf der Clientseite eingesetzt. Auch auf der Clientseite wird je Projekt ein POM erstellt. Das POM dient hierbei jedoch eher dazu alle Bibliotheken zu aktualisieren.
4.2.3 Implementierung von Unit - Tests
Wie schon in den vorherigen Kapiteln genannt, werden Unit - Tests vor der Erstellung der programmbezogenen Klassen entwickelt.
Hierzu bietet das JUnit - Framework zwei grundlegende Arten von Methoden an. Bei der ersten handelt es sich um die sogenannten assert - Methoden, die dazu dienen eine Bedingung sicherzustellen[13]. Dies wird, wie in der Abbildung zu sehen, dadurch erreicht, dass die Klasse des Unit - Tests bzw. sogar die einzelnen Methoden dieser auf die zu testenden Klassen referenzieren und Ausprägungen von Werten und Ergebnissen abprüfen.
Dies stellt das Testprinzip des Abgleichs von erwarteten Ergebnissen zu den Ist - Ergebnissen dar.
Ob nun eine Testmethode mehrere Methoden der zu testenden Klasse hintereinander aufruft oder die Ergebnisse einzelner Methoden gezielt abfragt, liegt in der Hand des Entwicklers. In der Regel ist ein möglichst modularisierter Test als Basis zu empfehlen. Es kann aber ebenfalls durchaus sinnvoll sein das Zusammenspiel mehrerer Methoden einer Klasse zu testen. Folgende generelle Assert - Methodennamen gibt es mit unterschiedlichen Signaturen (Eine Signatur besteht aus einem Methodennamen und der Definition von Übergabeparametern):
- assertEquals
- assertFalse
- assertNotNull
- assertNotSame
- assertNull
- assertSame
- assertTrue
Die zweite Methode ist die sogenannte Fail - Methode. Diese bewirkt, dass der Test definitiv fehl schlägt.
Das Framework von JUnit bietet darüberhinaus die Möglichkeit Annotationen zu verwenden. Annotationen sind übergeordnete Kommandos, denen teilweise (z.B. wie bei @Test) wie Methoden Parameter übergeben werden können. Sie erlauben es, Semantik explizit in den Quelltext einzubringen[14]. Sie werden vor Programmausführung erkannt und ausgeführt. Die Annotationen, die mit JUnit 4 eingeführt worden sind, sind folgende:
- @Test - Kennzeichnung einer Testmethode
- @Before - Kennzeichnung einer Methode, die vor jedem Testfall ausgeführt werden soll
- @After - Kennzeichnung einer Methode, die nach jedem Testfall ausgeführt werden soll
- @BeforeClass - Kennzeichnung einer Methode, die vor der Verwendung einer Klasse aufgerufen wird
- @AfterClass - Kennzeichnung einer Methode, die nach der Verwendung einer Klasse aufgerufen wird
- @Ignore - Die Methode wird ignoriert, solange diese Annotation gesetzt ist.
4.3 Continuous Integration
CI (Continuous Integration) beschreibt, wie der Begriff schon andeutet, eine kontinuierliche Integration von Programmteilen in ein Gesamtsystem. Sie stellt die Spitze der Testautomation dar[15]. Allerdings ist hierbei mehr gemeint als eine Ablage von Programmteilen in einem Softwareversionssystem. Es stellt vielmehr eine Möglichkeit dar mit der in kurzen Zeitabständen die bislang vorhandene Entwicklung zusammengefügt und getestet werden kann.
Die Abbildung beschreibt den Ablauf, wie mit dieser Technik umgegangen wird:
- 1. Der Entwickler erstellt den Quellcode, wobei hier wie in den Kapiteln zuvor Unit - Tests und danach die Funktionen erstellt werden.
- 2. In Abhängigkeit zur Komplexität bzw. zum Bedarf hat der Entwickler weiterhin die Möglichkeit manuelle Tests durchzuführen um ggf. mehrfaches Erstellen über den CIS (Continuous Integration Server) zu vermeiden. Bei diesen Tests muss der Entwickler nicht nur die erstellten Funktionen, sondern auch die dazugehörigen Unit - Tests validieren.
- 3. Der geänderte oder neu erstellte Quellcode (ebenfalls inklusive Unit - Tests) wird im Softwareversionssystem (CVS, SVN) abgelegt.
- 4. Der CIS erkennt die neuen Programmstände und ruft Tools (z.B. Maven) oder eigene Funktionen zur Neuerstellung des Projekts auf.
- 5. Nach dem Builden des Projekts ruft der CIS bzw. das Build - Tool automatisch alle Unit - Tests zu dem dazugehörigen Projekt auf. In Fehlerfällen ist es möglich über die Serverkonfiguration zu steuern, dass z.B. alle Projektbeteiligten eine Informationsmail über den fehlerhaften Stand des Projekts erhalten. Weitere Berichtswesensinformationen, wie eine Historie, einen Fehlertrend oder aber auch eine Übersicht über die abgeschlossenen Arbeiten einzelner Entwickler, sind je nach Konfiguration des CIS und der eingesetzten Tools möglich.
Die Vorteile dieser Vorgehensweise sind eine frühe Fehlererkennung auf der gesamten Projektebene, eine einfache Integration und Erstellung des Projektes und eine permanente Verfügbarkeit einer lauffähigen Programmversion zum aktuellen Entwicklungsstand. Daraus folgt, dass die Entwickler einen sauberen Programmierstil inklusive der häufig vernachlässigten Dokumentation in ihrem Arbeitsalltag befolgen müssen. Unter dem Aspekt der verbesserten Qualität sind ebenfalls die vor Beginn der Entwicklung geplanten Unit - Tests und eine einfache und schnelle Fehlerkorrektur zu nennen. Die Fehlerkorrektur ist aus dem Grund, dass der Entwickler noch mit dem Thema vertraut ist, unproblematisch und wesentlich zeiteffizienter zu bewerten.
5 Resümee
Die Bedeutung von Unit - Tests für CI ist so zu bewerten, dass ein Einsatz von Unit - Tests durchaus sinnvoll und effizient ist. Die Möglichkeit lediglich nur White - Box - Tests (Testtools wie PMD, Checkstyle und FindBugs) in einem CIS zu verwenden ist eher theoretischer Natur. Da die Rahmenbedingungen und die Infrastruktur in diesem Fall ebenfalls vorhanden wären, wäre es eine Vergeudung diese Ressourcen nicht zu nutzen und einen Teil der Vorteile der Testautomatisierung nicht auszuschöpfen. Interessanter ist hierbei die Entscheidungsfindung CI generell einzusetzen:
Testautomatisierung, wie sie hier beschrieben wurde, kann bei einer konsequenten Umsetzung zu einer besseren Softwarequalität führen. Allerdings sind hierbei die Vor- und Nachteile gegeneinander abzuwägen.
Für die Testautomatisierung mittels JUnit oder einem anderen Unit – Test spricht, dass über den ganzen Lebenszyklus gesehen eine Zeitersparnis erarbeitet werden kann, da wesentlich weniger Fehler bzw. eine schnellere Korrektur zu erwarten sind. Dies betrifft auch Programmerweiterungen, wenn bei diesen ebenfalls an Unit – Tests festgehalten wird.
Der positive Effekt, dass Fehler durch Seiteneffekte meistens sofort erkannt werden können, wird aber schon in größeren Projekten während der Realisierung spürbar. Besonders wenn, wie heutzutage üblich, mehrere Entwickler gleichzeitig an einem Projekt mit Hilfe eines Softwareverwaltungssystems arbeiten. In diesem Fall würden die Entwickler kontinuierlich ihre Programmstände einchecken, woraufhin automatisch ein neuer Build erstellt wird. Ist dieser nicht korrekt, können die Fehler zeitnah gesucht werden. Dies bringt eine weitere Zeitersparnis mit sich, da die Entwickler noch im aktuellen Projekt arbeiten und mit den letzten Programmänderungen und den vorhandenen Datenstrukturen vertraut sind. Eine Einarbeitungszeit entfällt hierbei.
Auch der Arbeitsorganisation kommt dieses Verfahren entgegen, sei es bei der eigenen Arbeitsplanung oder der Projektsteuerung. Es ist bei einem fehlerfreien Build davon auszugehen, dass die Stände, die eingecheckt worden sind, funktionstüchtig sind und somit die Aufgabe abgeschlossen werden kann. Der Entwickler wird gleichzeitig dazu angehalten, seine Arbeit so zu strukturieren, dass erst ein Teilbereich fertiggestellt wird, anstatt mehrere Klassen bzw. Programmteile gleichzeitig zu bearbeiten (ineffizient).
Negativ bei der Testautomatisierung zu bewerten ist, dass ggf. die Entwicklungsumgebungen ausgebaut und angepasst werden müssen Die Installation eines Applikationsservers und des CIS ist für eine parallele Entwicklung von mehreren Entwicklern zwingend erforderlich (siehe 4.2.2 Beschreibung einer möglichen Entwicklungsumgebung). Dies geht mit einem je nach Umfang und Unternehmensgröße zu bewertendem Investitionsvolumen einher. Auch wenn die Opensource – Produkte immer besser werden, lässt sich zwar der Kapitalbedarf verringern, jedoch nicht negieren, da die Einarbeitungszeit und ggf. Schulungen und anfängliche Verzögerungen während der Entwicklungstätigkeit zu berücksichtigen sind.
Diese Vorgehensweise erfordert des Weiteren die Disziplin aller Beteiligten. Die Gefahr, dass z.B. im Projektstress keine oder leere Unit - Tests erstellt werden, ist nicht zu unterschätzen. Die genannten Tools PMD, Checkstyle und FindBugs können hierbei nur unterstützen, aber nicht die Sorgfältigkeit und notwendige Gewissenhaftigkeit des Entwicklers ersetzen.
Durch die Testautomatisierung verlängert sich trotz Allem in der Regel die Entwicklungszeit eines Produkts. Genau dies kann externen Dienstleistern, wie z.B. Softwarehäusern Schwierigkeiten bereiten, da diese aufgrund der erhöhten Entwicklungszeiten den Kunden eine Software bzw. eine Entwicklungsarbeit ggf. zu einem höheren Preis als deren Konkurrenten anbieten.
Bei der Gegenüberstellung der Vor- und Nachteile überwiegen die Vorteile der Testautomatisierung kontra denen des manuellen Testens. Bei einem Produkt, welches nur für einen kurzfristigen Zeitraum eingesetzt werden soll und zeitnah benötigt wird, muss kritisch geprüft werden, ob sich der Einsatz dieser Techniken lohnt. Das theoretische Argument, dass alle Klassen modular und somit wiederverwendbar sein sollen, sollte natürlich berücksichtigt werden, wird in der Praxis in solchen Situationen jedoch häufig ignoriert. Spätestens jedoch, wenn abzusehen ist, dass sich die Anforderungen an die Anwendung kontinuierlich verändern können, stellt die Testautomatisierung ein probates Mittel zum Erstellen eines qualitativ hochwertigen Produkts dar, wobei bei sehr häufigen Änderungen ggf. schon während der Entwicklung Zeit gespart werden kann.
Das Argument der notwendigen Investitionskosten ist meines Erachtens bei einer regulären Entwicklungstätigkeit im Unternehmen ebenfalls zu vernachlässigen, da sich das Investitionskapital durch den langfristigen Aspekt amortisieren wird.
Mittel- bis langfristig werden die Entwickler ebenfalls erkennen, dass ihre Produkte souveräner laufen, wodurch ihnen selbst u.U. kritische Situationen im Projekteinsatz erspart bleiben (z.B. ein schwerwiegender Fehler in der Endphase eines Projekts).
Die höhere Entwicklungszeit sollte sich somit auch für Softwarehäuser u.U. eher als Qualitätsmerkmal und langfristige Investition als Preistreiberei darstellen lassen. Des Weiteren können beide Vorgehensweisen dem Kunden präsentiert werden, sodass er eine Entscheidungsgrundlage hat.
6 Fußnoten
- ↑ Vgl. Liggesmeyer (2002), S. 350ff
- ↑ Vgl. Lassmann (2006), S. 154
- ↑ Stahl (2007), S. 248
- ↑ Stahl (2007), S. 248
- ↑ Liggesmeyer (2002), S. 359
- ↑ Liggesmeyer (2002), S. 359f
- ↑ Liggesmeyer (2002), S. 360
- ↑ Lassmann (2006), S. 276
- ↑ Lassmann (2006), S. 276
- ↑ Vgl. Meffert (2006), S. 23f.
- ↑ Stahl (2007), S. 249
- ↑ Maven, passim
- ↑ Vgl. Meffert (2006), S. 20.
- ↑ Meffert (2006), S. 50.
- ↑ Stahl (2007), S. 248
7 Abkürzungsverzeichnis
| Abkürzung | Bedeutung |
|---|---|
| AT | Automatisierte Tests |
| CI | Continuous Integration |
| CIS | Continuous Integration Server |
| CVS | Current Version System |
| POM | Project Object Model |
| SVN | Subversion |
| TDD | Test - Driven Developtment |
| XML | Extended Markup Language |
| XP | Extreme Programming |
8 Abbildungsverzeichnis
| Bildnummer | Beschreibung |
|---|---|
| 1 | Fehlerzahlen in Entwicklungsphasen |
| 2 | Fehlerkorrekturkosten in Entwicklungsphasen |
| 3 | Verteilte Entwicklungsumgebung |
| 4 | Beispiel JUnit - Test |
| 5 | Ablauf CI |
9 Tabellenverzeichnis
| Tabellennummer | Beschreibung |
|---|---|
| 1 | Qualitätskriterien von Software |
| 2 | Definition Testebenen |
| 3 | Frameworks von Unit - Tests |
10 Literatur- und Quellenverzeichnis
| Lassmann (2006) | Lassmann, W. (2006), Wirtschaftsinformatik, 1. Aufl., Wiesbaden 2006 |
| Liggesmeyer (2002) | Liggesmeyer, P. (2002), Software-Qualität, Testen, Analysieren und Verifizieren von Software, Heidelberg; Berlin 2002 |
| Maven | http://www.sonatype.com/books/maven-book/reference/, Letztes Abrufdatum: 14.01.2010 |
| Meffert (2006) | Meffert, K. (2006), JUnit, Profi - Tipps, Siegen 2006 |
| Stahl (2007) | Stahl, T. (2007), Modellgetriebene Softwareentwicklung, Techniken, Engineering, Management, 2. Aufl., Heidelberg 2007 |

