Zum Inhalt springen

„Modultest“ – Versionsunterschied

aus Wikipedia, der freien Enzyklopädie
[ungesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
K Wikilink mit sichtbaren Klammern korrigiert
 
(267 dazwischenliegende Versionen von mehr als 100 Benutzern, die nicht angezeigt werden)
Zeile 1: Zeile 1:
Ein '''Modultest''' (auch von {{enS}} '''unit test''' als '''Unittest''' oder als '''Komponententest''' <!--Quelle z.&nbsp;B. http://www.softwarekompetenz.de/servlet/is/10127/?print=true--> bezeichnet) ist ein [[Softwaretest]], mit dem einzelne, abgrenzbare Teile von [[Computerprogramm]]en (z.&nbsp;B. ausgewählte Codeabschnitte, [[Modul (Software)|Module]], [[Unterprogramm]]e, [[Unit (Programmiersprache Pascal)|Units]] oder [[Klasse (objektorientierte Programmierung)|Klassen]]) überprüft werden. Testziel dieser häufig durch den Softwareentwickler selbst durchgeführten Softwaretests ist, deren technische Lauffähigkeit und die Korrektheit ihrer fachlichen (Teil-)Ergebnisse nachzuweisen.
Der '''Modultest''' (auch ''Komponententest'' oder engl. ''unit test'') ist Teil eines [[Softwareentwicklung|Softwareprozess]]es (z.B. nach dem Vorgehensmodell des [[Extreme Programming]]). Er dient zur [[Validierung (Informatik)|Validierung]] der Korrektheit von Modulen einer Software, z.B. von einzelnen Klassen. Als Voraussetzung für [[Refactoring]] kommt ihm besondere Bedeutung zu. Nach jeder Änderung sollte durch Ablaufenlassen aller ''[[Testfall|Testfälle]]'' nach [[Programmfehler]]n gesucht werden. Beim [[Testgetriebene Entwicklung|testgetriebenen Entwicklung]], auch [[TestFirst]]-Programmieren genannt, werden die Modultests parallel zum eigentlichen Quelltext erstellt und gepflegt. Dies ermöglicht bei automatisierten, reproduzierbaren Modultests die Auswirkungen von Änderungen sofort nachzuvollziehen. Der Programmierer entdeckt dadurch sicher ungewollte [[Wirkung (Informatik)|Nebeneffekte]] oder Fehler durch seine Änderung.


Der Ausdruck ''Modultest'' wird auch als eine frühe [[Softwaretest#Teststufen|Teststufe]] verstanden,<ref name="PKS">{{Literatur |Autor=Martin Pol, Tim Koomen, Andreas Spillner |Titel=Management und Optimierung des Testprozesses. Ein praktischer Leitfaden für erfolgreiches Testen von Software mit TPI und TMap |Auflage=2. |Verlag=dpunkt |Ort=Heidelberg |Datum=2002 |ISBN=3-89864-156-2}}</ref> in der die inneren, detailliertesten Komponenten der [[Software]] getestet werden. Siehe dazu auch die Grafik ''Stufen des V-Modells'' im [[V-Modell|Vorgehensmodell]] (nach [[Barry Boehm]]). Gemäß [[Software Validation & Verification Plan]] sind Modultests nur für Module mit geringer Kritikalität (die bei Fehlern den Benutzern nur geringe Unannehmlichkeiten bereiten) nicht notwendig.
Ein '''Komponententest''' ist ein ausführbares Codefragment, das das sichtbare Verhalten einer Komponente (z.B. einer Klasse) verifiziert und dem Programmierer eine unmittelbare Rückmeldung darüber gibt, ob die Komponente das geforderte Verhalten aufweist oder nicht. Durch diese Rückmeldung wird die [[Wartbarkeit]] z.B. durch [[Refactoring]] vereinfacht bzw. erst ermöglicht. Komponententests sind ein wesentlicher Bestandteil der [[Qualitätssicherung]] in der [[Softwareentwicklung]].


== Einordnung im Testprozess ==
Modultests sind eine geeignete Vorstufe zu [[Integrationstest|Integrationstests]], welche wiederum zum Testen mehrerer, von einander abhängiger Komponenten im Zusammenspiel geeignet sind. Im Gegensatz zu Modultests werden [[Integrationstest|Integrationstests]] meist manuell ausgeführt.
{{Hauptartikel|Softwaretest}}
Da Algorithmen auf Unitebene meist nur eine begrenzte Komplexität aufweisen und über klar definierte Schnittstellen aktiviert werden, können sie mit relativ wenigen [[Testfall|Testfällen]] weitgehend [[Testabdeckung|vollständig]] getestet werden. Dies gilt als Voraussetzung für die anschließende Teststufe [[Integrationstest]], um dort die Testfälle auf das integrierte Zusammenwirken größerer Funktionsteile oder der gesamten Anwendung ausrichten zu können; die modulspezifischen Detailkonstellationen lassen sich damit dort auf Stichproben beschränken, was die Anzahl der erforderlichen Testfälle drastisch reduziert.


Zum Vergleich: Ein Gerät wird erst dann als Ganzes getestet, wenn die Funktionsfähigkeit seiner Einzelteile als gesichert gilt.
==Testframeworks==
Testframeworks gibt es mittlerweile für fast jede [[Programmiersprache]]. Oft haben die Namen dieser Frameworks die Form xyzUnit (z. B. [[JUnit]] für [[Java (Programmiersprache)|Java]], siehe unten).


== Verfahren zur Testfalldefinition ==
===C===
Modultests zählen zu den [[White-Box-Test]]s. Das heißt, dass bei der Definition der Testfälle der zu testende Quellcode bekannt ist. Die Spezifikation der Software wird lediglich für die Bestimmung der Soll-Ergebnisse benutzt. Prinzipiell müssen alle Quellcode-Teile mindestens einmal ausgeführt werden. [[Kontrollflussorientierte Testverfahren#C0. Anweisungsüberdeckungstest (Statement Coverage)|Anweisungsüberdeckung]], [[Kontrollflussorientierte Testverfahren#C1. Zweigüberdeckungstest (Branch Coverage)|Zweigüberdeckung]] oder [[Kontrollflussorientierte Testverfahren#C2. Pfadüberdeckungstest (Path Coverage)|Pfadüberdeckung]] können dabei helfen festzustellen, welche Testfälle hierzu in der Theorie mindestens erforderlich sind (siehe dazu [[Kontrollflussorientierte Testverfahren]]). In der Praxis versucht man in aller Regel, das gesetzte Überdeckungsziel mit möglichst wenigen Testfällen zu erreichen, da alle Modultests auch laufend gepflegt werden müssen.
[[CUnit]] ist eine einfache Implementation des Frameworks für [[C (Programmiersprache)|C]]. Es ist ein offenes Projekt unter [[SourceForge]].


== Verfahren zum Erstellen von Modultests ==
===C++===
Üblicherweise orientieren sich alle Modultests an einem einheitlichen Grundaufbau. Dabei wird zunächst (1) ein Ausgangszustand initialisiert, hierauf (2) die zu testende Operation ausgeführt und zuletzt (3) das Ist-Ergebnis mit einem aus der Spezifikation abgeleiteten Sollwert verglichen. Für diese Vergleiche stellen die Test-Frameworks <code>assert</code>-Methoden (deutsch etwa: feststellen, versichern) zur Verfügung.
[[CppUnit]] ist die Portierung von JUnit auf [[C-Plusplus|C++]]. Ursprünglich wurde es von [[Michael Feathers]] geschrieben, ist jetzt aber ein offenes Projekt unter [[SourceForge]]. Da er allerdings den Eindruck hatte, dass [[CppUnit]] mittlerweile zu kompliziert zu installieren war, entschied sich Feathers, die abgespeckte Variante [[CppUnitLite]] zu schreiben. Weitere Frameworks für Komponententests sind [[CxxTest]] und [[CppTest]] (beides ebenfalls offene Projekte unter [[SourceForge]]) sowie die [http://www.boost.org/libs/test/doc/index.html Boost Test Library].


== Eigenschaften von Modultests ==
===Delphi===
=== Isolierung von Testobjekten ===
[[DUnit]] ist eine Portierung von [[JUnit]] für [[Borland Delphi]]. In der aktuellen Version "Delphi 2005" wurde es von Borland als fester Bestandteil in die Entwicklungsumgebung aufgenommen.
Modultests testen ein Modul isoliert, d.&nbsp;h. weitgehend ohne Interaktion mit anderen Modulen. Deshalb müssen oder können bei Modultests andere Module beziehungsweise externe Komponenten wie etwa eine [[Datenbank]], [[Datei]]en, [[Front-End und Back-End|Backendsysteme]] oder [[Unterprogramm]]e durch Hilfsobjekte simuliert werden, soweit das zu testende Modul ([[Prüfling]] oder Testobjekt) dies erfordert.


Dazu einsetzbare Hilfsobjekte lassen sich im Wesentlichen danach unterscheiden,<ref name="PKS"/>
===Java===
* ob sie ein ''aufzurufendes'' Modul ersetzen (Prüfling ist das aufrufende Modul; das Ersatzobjekt wird [[Stub (Programmierung)|‚Stub‘]] genannt),
[[JUnit]] wurde für die [[Programmiersprache]] [[Java (Programmiersprache)|Java]] von [[Erich Gamma]] und [[Kent Beck]] geschrieben. (weitere Werkzeuge für Modultests: [[HttpUnit]], [[Cactus]], ...)
* ob sie den ''Aufruf'' (die Umgebung) eines zu testenden Moduls/Unterprogramms ersetzen (Prüfling ist die Unterroutine, die den Aufruf simulierende Routine wird ‚Driver‘ genannt).


Wie vollständig die Hilfsroutine das Verhalten des Originals abbildet, etwa bei Plausibilitätsprüfungen oder bei der Rückgabe von Antwortcodes, ist durch entsprechendes Testfalldesign zu berücksichtigen. Besonders in objektorientierten Programmiersprachen lassen sich diesbezüglich weitere, detailliertere Kategorien von Hilfsobjekten unterscheiden, siehe [[Mock-Objekt]].
===Lingo (Macromedia Director) ===
Für die interpretierte Skriptsprache [[Lingo]] in [[Macromedia]]s Autorensystem [[Director]] gibt es das Framework [[LingoUnit]], welches ebenfalls unter [[SourceForge]] geführt wird.


Derartige Hilfsobjekte werden z.&nbsp;B. als [[Stellvertreter (Entwurfsmuster)|Stellvertreter]] implementiert und mittels [[Inversion of Control]] bereitgestellt. Ein Modul kann so meist einfacher getestet werden, als wenn alle Module bereits integriert sind, da in diesem Fall die Abhängigkeit der Einzelmodule mit in Betracht gezogen und im Testhandling berücksichtigt werden müsste. Auch sind derart isolierte Modultests schon möglich, wenn andere, eigentlich benötigte Komponenten für den Test noch nicht verfügbar sind.
===.NET===
[[NUnit]] ursprünglich eine 1:1 Portierung von [[JUnit]] auf die Plattform [[.NET]], insbesondere für [[C-Sharp|C#]] und [[VB.NET|Visual Basic .NET]]. Wurde mittlerweile mit spezifischen .NET Features erweitert neu geschrieben und unterstützt alle .NET Sprachen.


Vollständige Tests mit allen Komponenten in ihrer Originalversion sind Gegenstand der später stattfindenden [[Softwaretest#Teststufen|Integrations- und Systemtests]] – wobei ggf. im Modultest nicht erkannte Fehler (z.&nbsp;B. wegen identischer Falschannahmen für das Testobjekt und die Hilfsroutine) entdeckt werden sollten.
===PHP===
[[PHPUnit]] ist die Portierung von [[JUnit]] auf [[PHP]] und wurde von [[Sebastian Bergmann]] geschrieben. Es ist Bestandteil von [[PHP Extension and Application Repository|PEAR]].


=== Test des Vertrages und nicht der Algorithmen ===
[[Simpletest]] (http://www.lastcraft.com) von [[Marcus Baker]] ist ebenfalls eine Portierung von [[JUnit]], die um weitere Funktionen wie [[Mock-Objekt|Mock Objects]] und Funktionen zum Testen von Web-Seiten erweitert wurde.
Modultests testen gemäß dem [[Design by contract|Design-by-contract]]-Prinzip möglichst nicht die Interna einer Methode, sondern nur ihre externen Auswirkungen (Rückgabewerte, Ausgaben, Zustandsänderungen, Zusicherungen). Werden die internen Details der Methode geprüft (dies wird als White-Box-Testing bezeichnet), könnte der Test fehlschlagen, obwohl sich die externen Auswirkungen nicht geändert haben. Daher wird in der Regel das sogenannte [[Black-Box-Test]]ing empfohlen, bei dem man sich auf das Prüfen der externen Auswirkungen beschränkt.


== Automatisierte Modultests ==
===PL/SQL===
Mit der Verbreitung von [[Agile Softwareentwicklung|agilen Softwareentwicklungsmethoden]] und insbesondere [[Testgetriebene Entwicklung|testgetriebener Entwicklung]] ist es üblich geworden, Modultests möglichst automatisiert auszuführen. Dazu werden üblicherweise mit Hilfe von ''Test Frameworks'' wie beispielsweise [[JUnit]] Testprogramme geschrieben. Über die Test Frameworks werden die einzelnen Testklassen aufgerufen und deren Komponententests ausgeführt. Die meisten Test Frameworks geben eine grafische Zusammenfassung der Testergebnisse aus.
[http://utplsql.sourceforge.net/ utPLSQL] ist ein UnitTest-Framework für [[PL/SQL]] welches ebenfalls unter [[SourceForge]] geführt wird.


Automatisierte Modultests haben den Vorteil, dass sie einfach und kostengünstig ausgeführt und dass neue [[Programmfehler]] schnell gefunden werden können.
===Python===
Unittest ist fester Bestandteil der [[Python (Programmiersprache)|Python]] Standard Bibliothek


===Ruby===
== Vorteile ==
Unittest ist in der Standard-Bibliothek als <code>Test::Unit</code> oder <code>RUnit</code> verfügbar.


* Mittels automatisierter Unittests können im Schnitt 30 % der Fehler erkannt werden.<ref>{{Literatur |Autor=Steve McConnell |Titel=Code Complete |Auflage=2 |Verlag=Microsoft Press |Ort=Redmond |Datum=2004-07-02 |Sprache=en |ISBN=978-0735619678 |Seiten=470 |Zitat=Unit test: Lowest Rate 15%, Modal Rate 30%, Highest Rate 50%}}</ref> Bei der Verwendung von [[Testgetriebene Entwicklung|testgetriebener Entwicklung]] können im Schnitt 45 % und im besten Fall 85 % der Fehler vermieden werden.<ref>{{Literatur |Autor=Capers Jones |Titel=Software Engineering Best Practices |Verlag=McGraw-Hill |Ort=New York City |Datum=2010 |Sprache=en |ISBN=978-0-07-162162-5 |Umfang=660 |Kapitel=9 Software Quality |Seiten=330,602 |Zitat="the defect removal efficiency of TDD is higher than many forms of testing and can top 85 percent"}}</ref>
===Smalltalk===
* Fehler werden durch Modultests bereits während der Entwicklung erkannt. Die durch Unittests vermiedenen Fehlerkosten sind daher gemäß der Rule of Ten<ref>{{Internetquelle |url=https://www.sixsigmablackbelt.de/fehlerkosten-10er-regel-zehnerregel-rule-of-ten/ |titel=Fehlerkosten 10er Regel Zehnerregel (Rule of ten) |werk=sixsigmablackbelt.de |hrsg=Roland Schnurr |abruf=2022-04-05}}</ref> um ein vielfaches höher als bei späteren Teststufen, was Unittests zur effizientesten Teststufe machen.
Das vermutlich erste [[Framework]] zum Erstellen von Komponententests ([[SUnit]]) wurde von [[Kent Beck]] für die [[Programmiersprache]] [[Smalltalk (Programmiersprache)|Smalltalk]] geschrieben. Die Idee wurde schnell auf andere Programmiersprachen übertragen.
* Im Falle eines Fehlers kann dieser sehr viel genauer eingegrenzt und damit schneller gefunden und behoben werden.
* Die Tests erfüllen den Zweck einer [[Lebende Dokumentation|lebenden Dokumentation]]. In Kombination mit einer sinnvollen Benennung der Objekte ([[Clean Code]]) können zusätzliche Dokumentationsmaßnahmen entfallen.
* Da einzelne Module nur wenige mögliche Codeausführungspfade besitzen, müssen viel weniger mögliche kombinatorische Ausführungspfade berücksichtigt werden, als bei anderen Testarten. Übergeordnete Tests können sich stichprobenartig auf die wichtigsten Ausführungspfade konzentrieren und damit deutlich reduziert werden.
* Da nur einzelne Module getestet werden, können Modultests, oft um mehrere Größenordnungen, schneller und damit öfter (bzw. kontinuierlich) ausgeführt werden als andere Testarten.
* Wenn Fehler mit einem Test abgesichert werden, wird verhindert, dass dieser Fehler erneut auftritt.
* Durch die Fehlerreduktion ergeben sich Geschwindigkeitsvorteile in der Entwicklung in mittleren bis großen Softwareprojekten.
* Da Abhängigkeiten zwingend vermieden werden müssen, um einen Modultest zu ermöglichen, bleibt der Code verhältnismäßig schnell änderbar. Hierdurch kann schneller auf wechselnde Anforderungen reagiert werden.
* Da automatisch ausgeführte Tests um mehrere Größenordnungen schneller sind als manuelle Tests, reduziert sich der Zeitaufwand für das Testen deutlich. Hierdurch können [[Entwicklungsstadium (Software)|Entwicklungsstufen]] schneller durchlaufen und die Release-Zyklen verkürzt werden.


===Tcl===
== Nachteile ==
Die Tcllib enthält das Modul tcltest für Modultests. Auch andere Test-Frameworks wurden in [[Tcl]] geschrieben, bekannt ist etwa DejaGnu, mit dem der [[gcc]]-Compiler getestet wird. Zudem kann man in wenigen Zeilen ein "Framework" selbst erstellen:
proc test {command expected} {
catch {uplevel 1 $command} res
if {$res ne $expected} {puts "$command->$res, not $expected"}
}
Tests (in eigenen Quelldateien, oder direkt beim Code) sehen dann so aus: man gibt eine Anweisung und das erwartete Ergebnis an. Wenn ein unerwartetes Ergebnis ausgewertet wird, so wird dies angezeigt:
test {expr 3 + 4} 7


* Bei Implementierung ''neuer'' Funktionalität muss nicht nur die Funktion implementiert, sondern es müssen auch die dazugehörenden Tests vorbereitet/definiert werden. Es ergibt sich somit ein oft mehrfacher Implementierungsaufwand.
===Visual Basic 6===
* Bei ''Änderungen'' müssen nicht nur die geänderten Funktionalitäten, sondern auch die dazugehörenden Tests angepasst werden. Insbesondere bei der Entwicklung von Prototypen, bei der sich die Codebasis schnell verändert, ist das Testen daher oft hinderlich.
Die deutsche Firma Maaß Computertechnik aus Bochum hat das xUnit Framework für Visual Basic 6 implementiert und bietet dieses unter http://www.vbunit.org/ an.
* Da die Funktionalität von den Tests verwendet wird, ist in [[Integrierte Entwicklungsumgebung|IDEs]] schwerer ersichtlich, ob eine Funktionalität nicht mehr anderweitig verwendet wird und daher entfernt werden kann.
* Weisen die Tests untereinander Abhängigkeiten auf (z.&nbsp;B. durch gemeinsame Testdaten), so können einzelne Änderungen an der Codebasis eine Vielzahl von Tests beeinflussen, was den Änderungsaufwand mit der Größe der Codebasis exponentiell erhöht.


== Grenzen von Modultests ==
vbUnit ist nicht vollkommen Open Source. In der kostenpflichtigen Version 3 Professional erhält man das Unit Testing Framework für Visual Basic 6 inklusive einem Microsoft Visual Studio 6 Add-on.
{{Belege fehlen}}
Modultests können (wie jeder Test) die Fehlerfreiheit des getesteten Moduls nicht garantieren oder nachweisen, sondern lediglich unterstützen. Die Grenzen von Modultests liegen notwendigerweise darin, dass nur solche Fehler gefunden werden können, zu deren Entdeckung die verwendeten Tests geeignet sind. Eine Softwarekomponente, die „grün“ testet, ist also nicht unbedingt fehlerfrei.


Das Merkmal von Code, „grün“ zu testen, und durchaus auch der Wunsch nach diesem Ergebnis, könnte dazu führen, dass tatsächlich (unbewusst) nur so viel getestet wird, bis alle Tests „grün“ sind. Module, die keine fehlschlagenden Modultests haben, als fehlerfrei zu behandeln, ist ein [[Fehlschluss]] in der Praxis testgetriebener Entwicklung.
Die Basic Version von vbUnit wird unter der GNU Lesser Public Licence (LGPL) angeboten. D.h. dass man zu dieser Version sowohl die kompilierten Komponenten als auch den Quellcode erhält. Der TestRunner und das Add-on für Microsofts Visual Studio 6 in der Professional Version sind kostenpflichtig und nicht Open Source.


Um eine ausreichende [[Testabdeckung]] zu erzielen, lohnt es sich u.&nbsp;U., vor dem Erstellen der Testfälle [[Refactoring]]-Maßnahmen anzuwenden. Dies erst nach abgeschlossenen Modultests (für den alten Code) zu tun, würde (wie jede Änderung im Code) neue Fehlerrisiken bergen und deshalb wiederholtes Testen erforderlich machen.
==Literatur==
*Paul Hamill, ''Unit Test Frameworks'' (engl.), O'Reilly Media, 2004, ISBN 0-5960-0689-6


Wenn der Autor von Modultests mit dem Autor der Module identisch ist, können Denkfehler in der Implementierung auch im Test erscheinen und nicht aufgedeckt werden. Wenn es sich um dieselbe Person handelt, wird dies auch nicht dadurch ausgeschlossen, dass die Tests zuerst entwickelt werden, da sowohl die beabsichtigte Funktionsweise des Codes als auch seine zukünftige Gestalt bereits im Denken des Testautors und späteren Codeautors präsent sein können. Dies kann im [[Extreme Programming]] durch „Test Ping-Pong“ abgefangen werden, bei der sich Entwickler bei der Implementierung der Funktionalität und der Tests abwechseln.
==Weblinks==
*{{dmoz|Computers/Programming/Languages/Java/Development_Tools/Performance_and_Testing/Unit_Testing/|Unit-Testing (engl.)}}
*[http://www.EvoComp.de/softwareentwicklung/unit-tests/unittests.html Einführung] in die Prinzipien von Unit-Tests
*[http://www.zuerich3.ch/unitTesting/index.html Einführung] in Modultests mit Visual Basic 6.0
*[http://junit.sourceforge.net/doc/testinfected/testing.htm Artikel] zum Thema Komponententests unter JAVA
*[http://www.verifysoft.de/de_unittest.html Artikel] „Bessere Codequalität durch Unit-Tests“
*[http://www.hitex.de/download/tessy/data/WP-TESSY-0101.pdf White Paper] „Unit Test of Embedded Software“


Bei der Entwicklung von Modultests können Testfälle entstehen, die der Zielsetzung und dem Charakter von Modultests nicht oder nur zum Teil entsprechen. Wie bei der Programmierung existieren daher auch für die Entwicklung von Modultests ''[[Anti-Pattern]]'', die möglichst vermieden werden sollten.<ref>[https://www.yegor256.com/2018/12/11/unit-testing-anti-patterns.html Modultest Anti-Pattern]</ref>
[[Kategorie:Testen (Software)]]


== Siehe auch ==
[[en:Unit test]]
* [[Liste von Modultest-Software]]
[[es:Prueba unitaria]]
* [[Testgetriebene Entwicklung]]
[[fr:Test unitaire]]
* [[Behavior Driven Development|Verhaltensgetriebene Softwareentwicklung]]
[[he:בדיקות יחידה]]

[[pl:Unit test]]
== Literatur ==
[[ru:Юнит-тестирование]]
* {{Literatur
|Autor=Paul Hamill
|Titel=Unit Test Frameworks. (A Language Independent Overview)
|Verlag=O’Reilly Media
|Ort=Beijing u.&nbsp;a.
|Datum=2004
|ISBN=0-596-00689-6
|Sprache=en}}
* {{Literatur
|Autor=Gerard Meszaros
|Titel=xUnit Test Patterns. Refactoring Test Code
|Verlag=Addison-Wesley
|Ort=Upper Saddle River NJ u.&nbsp;a.
|Datum=2007
|ISBN=978-0-13-149505-0
|Sprache=en}}
* {{Literatur
|Autor=Andreas Spillner, Tilo Linz
|Titel=Basiswissen Softwaretest. Aus- und Weiterbildung zum Certified Tester. Foundation Level nach ISTQB-Standard
|Auflage=4., überarbeitete und aktualisierte
|Verlag=dpunkt-Verlag
|Ort=Heidelberg
|Datum=2010
|ISBN=978-3-89864-642-0}}

== Weblinks ==
* {{dmoz|Computers/Programming/Software_Testing/Unit_Testing/|Unit-Testing}} (englisch)
* [http://www.evocomp.de/softwareentwicklung/unit-tests/unittests.html Einführung in die Prinzipien von Unit-Tests]
* [https://www.informatik-aktuell.de/entwicklung/methoden/was-ist-ein-guter-unit-test-und-wie-entwickelt-man-ihn.html Entwicklung von Modul Tests mit Beispielen], Autor Markus Lenger, in: [[Informatik Aktuell (Magazin)|Informatik Aktuell]]
* [http://junit.sourceforge.net/doc/testinfected/testing.htm Artikel zum Thema Komponententests unter Java] (englisch)

== Einzelnachweise ==
<references />

[[Kategorie:Testen (Software)]]

Aktuelle Version vom 11. Juni 2025, 20:21 Uhr

Ein Modultest (auch von englisch unit test als Unittest oder als Komponententest bezeichnet) ist ein Softwaretest, mit dem einzelne, abgrenzbare Teile von Computerprogrammen (z. B. ausgewählte Codeabschnitte, Module, Unterprogramme, Units oder Klassen) überprüft werden. Testziel dieser häufig durch den Softwareentwickler selbst durchgeführten Softwaretests ist, deren technische Lauffähigkeit und die Korrektheit ihrer fachlichen (Teil-)Ergebnisse nachzuweisen.

Der Ausdruck Modultest wird auch als eine frühe Teststufe verstanden,[1] in der die inneren, detailliertesten Komponenten der Software getestet werden. Siehe dazu auch die Grafik Stufen des V-Modells im Vorgehensmodell (nach Barry Boehm). Gemäß Software Validation & Verification Plan sind Modultests nur für Module mit geringer Kritikalität (die bei Fehlern den Benutzern nur geringe Unannehmlichkeiten bereiten) nicht notwendig.

Einordnung im Testprozess

[Bearbeiten | Quelltext bearbeiten]

Da Algorithmen auf Unitebene meist nur eine begrenzte Komplexität aufweisen und über klar definierte Schnittstellen aktiviert werden, können sie mit relativ wenigen Testfällen weitgehend vollständig getestet werden. Dies gilt als Voraussetzung für die anschließende Teststufe Integrationstest, um dort die Testfälle auf das integrierte Zusammenwirken größerer Funktionsteile oder der gesamten Anwendung ausrichten zu können; die modulspezifischen Detailkonstellationen lassen sich damit dort auf Stichproben beschränken, was die Anzahl der erforderlichen Testfälle drastisch reduziert.

Zum Vergleich: Ein Gerät wird erst dann als Ganzes getestet, wenn die Funktionsfähigkeit seiner Einzelteile als gesichert gilt.

Verfahren zur Testfalldefinition

[Bearbeiten | Quelltext bearbeiten]

Modultests zählen zu den White-Box-Tests. Das heißt, dass bei der Definition der Testfälle der zu testende Quellcode bekannt ist. Die Spezifikation der Software wird lediglich für die Bestimmung der Soll-Ergebnisse benutzt. Prinzipiell müssen alle Quellcode-Teile mindestens einmal ausgeführt werden. Anweisungsüberdeckung, Zweigüberdeckung oder Pfadüberdeckung können dabei helfen festzustellen, welche Testfälle hierzu in der Theorie mindestens erforderlich sind (siehe dazu Kontrollflussorientierte Testverfahren). In der Praxis versucht man in aller Regel, das gesetzte Überdeckungsziel mit möglichst wenigen Testfällen zu erreichen, da alle Modultests auch laufend gepflegt werden müssen.

Verfahren zum Erstellen von Modultests

[Bearbeiten | Quelltext bearbeiten]

Üblicherweise orientieren sich alle Modultests an einem einheitlichen Grundaufbau. Dabei wird zunächst (1) ein Ausgangszustand initialisiert, hierauf (2) die zu testende Operation ausgeführt und zuletzt (3) das Ist-Ergebnis mit einem aus der Spezifikation abgeleiteten Sollwert verglichen. Für diese Vergleiche stellen die Test-Frameworks assert-Methoden (deutsch etwa: feststellen, versichern) zur Verfügung.

Eigenschaften von Modultests

[Bearbeiten | Quelltext bearbeiten]

Isolierung von Testobjekten

[Bearbeiten | Quelltext bearbeiten]

Modultests testen ein Modul isoliert, d. h. weitgehend ohne Interaktion mit anderen Modulen. Deshalb müssen oder können bei Modultests andere Module beziehungsweise externe Komponenten wie etwa eine Datenbank, Dateien, Backendsysteme oder Unterprogramme durch Hilfsobjekte simuliert werden, soweit das zu testende Modul (Prüfling oder Testobjekt) dies erfordert.

Dazu einsetzbare Hilfsobjekte lassen sich im Wesentlichen danach unterscheiden,[1]

  • ob sie ein aufzurufendes Modul ersetzen (Prüfling ist das aufrufende Modul; das Ersatzobjekt wird ‚Stub‘ genannt),
  • ob sie den Aufruf (die Umgebung) eines zu testenden Moduls/Unterprogramms ersetzen (Prüfling ist die Unterroutine, die den Aufruf simulierende Routine wird ‚Driver‘ genannt).

Wie vollständig die Hilfsroutine das Verhalten des Originals abbildet, etwa bei Plausibilitätsprüfungen oder bei der Rückgabe von Antwortcodes, ist durch entsprechendes Testfalldesign zu berücksichtigen. Besonders in objektorientierten Programmiersprachen lassen sich diesbezüglich weitere, detailliertere Kategorien von Hilfsobjekten unterscheiden, siehe Mock-Objekt.

Derartige Hilfsobjekte werden z. B. als Stellvertreter implementiert und mittels Inversion of Control bereitgestellt. Ein Modul kann so meist einfacher getestet werden, als wenn alle Module bereits integriert sind, da in diesem Fall die Abhängigkeit der Einzelmodule mit in Betracht gezogen und im Testhandling berücksichtigt werden müsste. Auch sind derart isolierte Modultests schon möglich, wenn andere, eigentlich benötigte Komponenten für den Test noch nicht verfügbar sind.

Vollständige Tests mit allen Komponenten in ihrer Originalversion sind Gegenstand der später stattfindenden Integrations- und Systemtests – wobei ggf. im Modultest nicht erkannte Fehler (z. B. wegen identischer Falschannahmen für das Testobjekt und die Hilfsroutine) entdeckt werden sollten.

Test des Vertrages und nicht der Algorithmen

[Bearbeiten | Quelltext bearbeiten]

Modultests testen gemäß dem Design-by-contract-Prinzip möglichst nicht die Interna einer Methode, sondern nur ihre externen Auswirkungen (Rückgabewerte, Ausgaben, Zustandsänderungen, Zusicherungen). Werden die internen Details der Methode geprüft (dies wird als White-Box-Testing bezeichnet), könnte der Test fehlschlagen, obwohl sich die externen Auswirkungen nicht geändert haben. Daher wird in der Regel das sogenannte Black-Box-Testing empfohlen, bei dem man sich auf das Prüfen der externen Auswirkungen beschränkt.

Automatisierte Modultests

[Bearbeiten | Quelltext bearbeiten]

Mit der Verbreitung von agilen Softwareentwicklungsmethoden und insbesondere testgetriebener Entwicklung ist es üblich geworden, Modultests möglichst automatisiert auszuführen. Dazu werden üblicherweise mit Hilfe von Test Frameworks wie beispielsweise JUnit Testprogramme geschrieben. Über die Test Frameworks werden die einzelnen Testklassen aufgerufen und deren Komponententests ausgeführt. Die meisten Test Frameworks geben eine grafische Zusammenfassung der Testergebnisse aus.

Automatisierte Modultests haben den Vorteil, dass sie einfach und kostengünstig ausgeführt und dass neue Programmfehler schnell gefunden werden können.

  • Mittels automatisierter Unittests können im Schnitt 30 % der Fehler erkannt werden.[2] Bei der Verwendung von testgetriebener Entwicklung können im Schnitt 45 % und im besten Fall 85 % der Fehler vermieden werden.[3]
  • Fehler werden durch Modultests bereits während der Entwicklung erkannt. Die durch Unittests vermiedenen Fehlerkosten sind daher gemäß der Rule of Ten[4] um ein vielfaches höher als bei späteren Teststufen, was Unittests zur effizientesten Teststufe machen.
  • Im Falle eines Fehlers kann dieser sehr viel genauer eingegrenzt und damit schneller gefunden und behoben werden.
  • Die Tests erfüllen den Zweck einer lebenden Dokumentation. In Kombination mit einer sinnvollen Benennung der Objekte (Clean Code) können zusätzliche Dokumentationsmaßnahmen entfallen.
  • Da einzelne Module nur wenige mögliche Codeausführungspfade besitzen, müssen viel weniger mögliche kombinatorische Ausführungspfade berücksichtigt werden, als bei anderen Testarten. Übergeordnete Tests können sich stichprobenartig auf die wichtigsten Ausführungspfade konzentrieren und damit deutlich reduziert werden.
  • Da nur einzelne Module getestet werden, können Modultests, oft um mehrere Größenordnungen, schneller und damit öfter (bzw. kontinuierlich) ausgeführt werden als andere Testarten.
  • Wenn Fehler mit einem Test abgesichert werden, wird verhindert, dass dieser Fehler erneut auftritt.
  • Durch die Fehlerreduktion ergeben sich Geschwindigkeitsvorteile in der Entwicklung in mittleren bis großen Softwareprojekten.
  • Da Abhängigkeiten zwingend vermieden werden müssen, um einen Modultest zu ermöglichen, bleibt der Code verhältnismäßig schnell änderbar. Hierdurch kann schneller auf wechselnde Anforderungen reagiert werden.
  • Da automatisch ausgeführte Tests um mehrere Größenordnungen schneller sind als manuelle Tests, reduziert sich der Zeitaufwand für das Testen deutlich. Hierdurch können Entwicklungsstufen schneller durchlaufen und die Release-Zyklen verkürzt werden.
  • Bei Implementierung neuer Funktionalität muss nicht nur die Funktion implementiert, sondern es müssen auch die dazugehörenden Tests vorbereitet/definiert werden. Es ergibt sich somit ein oft mehrfacher Implementierungsaufwand.
  • Bei Änderungen müssen nicht nur die geänderten Funktionalitäten, sondern auch die dazugehörenden Tests angepasst werden. Insbesondere bei der Entwicklung von Prototypen, bei der sich die Codebasis schnell verändert, ist das Testen daher oft hinderlich.
  • Da die Funktionalität von den Tests verwendet wird, ist in IDEs schwerer ersichtlich, ob eine Funktionalität nicht mehr anderweitig verwendet wird und daher entfernt werden kann.
  • Weisen die Tests untereinander Abhängigkeiten auf (z. B. durch gemeinsame Testdaten), so können einzelne Änderungen an der Codebasis eine Vielzahl von Tests beeinflussen, was den Änderungsaufwand mit der Größe der Codebasis exponentiell erhöht.

Grenzen von Modultests

[Bearbeiten | Quelltext bearbeiten]

Modultests können (wie jeder Test) die Fehlerfreiheit des getesteten Moduls nicht garantieren oder nachweisen, sondern lediglich unterstützen. Die Grenzen von Modultests liegen notwendigerweise darin, dass nur solche Fehler gefunden werden können, zu deren Entdeckung die verwendeten Tests geeignet sind. Eine Softwarekomponente, die „grün“ testet, ist also nicht unbedingt fehlerfrei.

Das Merkmal von Code, „grün“ zu testen, und durchaus auch der Wunsch nach diesem Ergebnis, könnte dazu führen, dass tatsächlich (unbewusst) nur so viel getestet wird, bis alle Tests „grün“ sind. Module, die keine fehlschlagenden Modultests haben, als fehlerfrei zu behandeln, ist ein Fehlschluss in der Praxis testgetriebener Entwicklung.

Um eine ausreichende Testabdeckung zu erzielen, lohnt es sich u. U., vor dem Erstellen der Testfälle Refactoring-Maßnahmen anzuwenden. Dies erst nach abgeschlossenen Modultests (für den alten Code) zu tun, würde (wie jede Änderung im Code) neue Fehlerrisiken bergen und deshalb wiederholtes Testen erforderlich machen.

Wenn der Autor von Modultests mit dem Autor der Module identisch ist, können Denkfehler in der Implementierung auch im Test erscheinen und nicht aufgedeckt werden. Wenn es sich um dieselbe Person handelt, wird dies auch nicht dadurch ausgeschlossen, dass die Tests zuerst entwickelt werden, da sowohl die beabsichtigte Funktionsweise des Codes als auch seine zukünftige Gestalt bereits im Denken des Testautors und späteren Codeautors präsent sein können. Dies kann im Extreme Programming durch „Test Ping-Pong“ abgefangen werden, bei der sich Entwickler bei der Implementierung der Funktionalität und der Tests abwechseln.

Bei der Entwicklung von Modultests können Testfälle entstehen, die der Zielsetzung und dem Charakter von Modultests nicht oder nur zum Teil entsprechen. Wie bei der Programmierung existieren daher auch für die Entwicklung von Modultests Anti-Pattern, die möglichst vermieden werden sollten.[5]

  • Paul Hamill: Unit Test Frameworks. (A Language Independent Overview). O’Reilly Media, Beijing u. a. 2004, ISBN 0-596-00689-6 (englisch).
  • Gerard Meszaros: xUnit Test Patterns. Refactoring Test Code. Addison-Wesley, Upper Saddle River NJ u. a. 2007, ISBN 978-0-13-149505-0 (englisch).
  • Andreas Spillner, Tilo Linz: Basiswissen Softwaretest. Aus- und Weiterbildung zum Certified Tester. Foundation Level nach ISTQB-Standard. 4., überarbeitete und aktualisierte Auflage. dpunkt-Verlag, Heidelberg 2010, ISBN 978-3-89864-642-0.

Einzelnachweise

[Bearbeiten | Quelltext bearbeiten]
  1. a b Martin Pol, Tim Koomen, Andreas Spillner: Management und Optimierung des Testprozesses. Ein praktischer Leitfaden für erfolgreiches Testen von Software mit TPI und TMap. 2. Auflage. dpunkt, Heidelberg 2002, ISBN 3-89864-156-2.
  2. Steve McConnell: Code Complete. 2. Auflage. Microsoft Press, Redmond 2004, ISBN 978-0-7356-1967-8, S. 470 (englisch): “Unit test: Lowest Rate 15%, Modal Rate 30%, Highest Rate 50%”
  3. Capers Jones: Software Engineering Best Practices. McGraw-Hill, New York City 2010, ISBN 978-0-07-162162-5, 9 Software Quality, S. 330,602 (englisch, 660 S.): "the defect removal efficiency of TDD is higher than many forms of testing and can top 85 percent"
  4. Fehlerkosten 10er Regel Zehnerregel (Rule of ten). In: sixsigmablackbelt.de. Roland Schnurr, abgerufen am 5. April 2022.
  5. Modultest Anti-Pattern