![]() |
|
URL dieses Artikels:
zu Ausgabe:
1.2005
TDD in der Praxis
Werkzeuge und Einführung
von Olga Kolov und Frank Müller
Im ersten Teil dieses Artikels (Linux Enterprise 10.2004) haben wir Ihnen die Idee, das Konzept sowie Argumentationshilfen für verschiedene Zielgruppen rund um das Test Driven Development vorgestellt. Dies sollte für eine erste Infizierung genügen. Nun besteht das Test Driven Development jedoch nicht nur aus einigen wenigen TestCases. Vielmehr muss es den Entwicklungsprozess begleiten und weitestgehend automatisiert werden. Dies bedarf entsprechender Werkzeuge. Ebenso wichtig ist richtiges Testen, um Fehlverhalten frühzeitig aufzudecken. Beide behandelt der folgende zweite Teil zum TDD.
Wie sagte schon George Bernard Shaw: Take care to get what you like or you will be forced to like what you get. Diese Weisheit trifft auch in vielerlei Hinsicht auf die Software-Entwicklung zu. In unserem Kontext ist es die Qualität von Software, speziell der Nachweis der technischen und funktionalen Aspekte. Dieses lässt sich weder durch meditatives Betrachten des Quellcodes noch durch ein einfaches Herumklicken und -tippen erreichen. Wichtig sind an dieser Stelle Werkzeuge, die den Entwickler bei der Sicherstellung der Qualität unterstützen. Diese Werkzeuge sind reichlich vorhanden und decken alle vier Testebenen ab. Die erste ist der Modultest - bisher auch als Unit Test bezeichnet. Dieser Test wird durch den Entwickler unter Laborbedingungen ausgeführt, also seinem Arbeitsplatz oder einfachen dafür dedizierten System. Er soll nachweisen, dass ein Modul (Komponente, Programmsegment) seinen technischen Spezifikationen entspricht. Die Basis ist der technische Entwurf. Während der Integration werden die bereits getesteten Module miteinander verknüpft. Der Integrationstest ist ein vom Entwickler bzw. dem Integrationsteam mit Unterstützung der Entwickler ebenfalls unter Laborbedingungen ausgeführter Test. Mit dem Integrationstest soll nachgewiesen werden, dass ein logischer Block von Programmteilen den in den technischen Spezifikationen festgestellten Anforderungen entspricht. Tests werden dabei nur für die Modul-übergreifenden Abläufe (Schnittstellen) durchgeführt. Basis ist auch hier der technische Entwurf. Unter realen Bedingungen, aber noch unter Ausschluss des Auftraggebers im Sinne der Abnahme, findet der Systemtest statt. Sein Ziel ist der Nachweis, dass das entwickelte System oder Teile davon den in den funktionalen und technischen Spezifikationen (Fachkonzept und DV-Konzept) festgelegten Anforderungen entspricht. Basis des Systemtests ist der funktionale Entwurf. Die letzte Testebene ist der Abnahmetest. Dieser wird von Anwendern und Systemadministratoren in der produktiven Umgebung und mit echten Daten ausgeführt und soll nachweisen, dass das entwickelte System den funktionalen und qualitativen Anforderungen entspricht. Basis ist hier erneut der funktionale Entwurf. Auf allen Ebenen macht es Sinn, die Tests zu automatisieren. So können sie schnell und unkompliziert wiederholt werden und den Nachweis erbringen, dass sich Änderungen am Code oder dem System nicht negativ auf das System auswirken. Mit jeder Ebene steigt dabei die Komplexität und eine Wiederverwendbarkeit von Test erfordert eine Konfigurierbarkeit, damit die Tests auf den jeweils neuen Kontext angepasst werden können. Die im Folgenden vorgestellten Werkzeuge unterstützen diese Tests, mal aus Sicht eines Entwicklers in Form programmierter Verifikation, mal durch die Aufzeichnung von Bedienfolgen für den Integrator. Alles FIT? Vielfach werden mit dem Test Driven Development die Unit Tests von Kent Beck verbunden. Diese Ansicht ist zwar nicht ganz unberechtigt, hat sein Test-Framework unter Smalltalk die Begeisterung erst ausgelöst. Eine Alternative ist jedoch FIT von Ward Cunningham [FIT]. Ward ist vielen sicherlich von seiner bedeutendsten Entwicklung bekannt, der Idee der Wikis als sehr einfache und offene Content-Management- Systeme. Sein Konzept ist der Test der Geschäftslogik parametrisiert aus einer Webseite heraus. So kann der Anwender schnell erfassen, ob alle Testfälle fehlerfrei durchlaufen werden und wenn nicht, was denn sein Test als Ergebnis zurückgeliefert hat. Dabei werden die Tests innerhalb einer HTML-Seite in Tabellen definiert, die neben dieser Definition den konkreten Testfall, optionale Parameter für diesen Testfall sowie das erwartete Ergebnis enthalten. Dabei bestimmt die Art des zuvor entwickelten Tests - im FIT-Sprachgebrauch ein Fixture - wie die Spalten interpretiert werden. So kann die senkrechte Anordnung eine Menge gleicher Funktionen pro Spalte mit unterschiedlichen Parametern in den ersten Spalten bedeuten. Eine andere Variante beschreibt eine schrittweise Bedienung eines Programms mit jeder Zeile der Tabelle. Ein CGI-Programm als Wrapper für die verschiedenen Sprachen parst beim Aufruf die HTML-Seiten und die darin enthaltenen Tabellen. Basierend auf dem Fixture werden nun die Tests ausgeführt und die Seite neu erzeugt. In diesem Fall sind die Ergebnisfelder jedoch grün hinterlegt, wenn alles fehlerfrei durchgelaufen ist, und rot, wenn das Ergebnis vom erwarteten Wert abweicht. Die FIT-Fixture-Typen als Basis der Testklassen fokussieren auf Tests von Methoden in Abhängigkeit von Parametern, auf den Test kompletter Klassen oder auf Bedienabläufe innerhalb des Programms. Ein eigener Test - hier auf Basis der ColumnFixture schreibt sich nun wie folgt: import fit.ColumnFixture; Weiter wird eine HTML-Datei erstellt: <TABLE BORDER CELLSPACING=0 CELLPADDING=3 > ![]() Bild 1: Testtabelle vor einem Testlauf Durch das eingebettete CGI oder mit einem einfachen Aufruf auf der Kommandozeile kann das FIT-Framework aktiviert werden: java fit.FileRunner input-file.html output-file.html Der Durchlauf der Tests wird auf der Konsole ähnlich wie bei JUnit mit einer Meldung in der Form 29 right, 8 wrong, 0 ignored, 2 exceptions beendet. Die Darstellung in der HTML-Seite macht das Ergebnis detaillierter sichtbar, mal erfolgreicher, mal weniger erfolgreich. ![]() Bild 2: Erfolgreicher Durchlauf eines Column Fixture ![]() Bild 3: Fehlerhafter Durchlauf eines Action Fixture Diese Form der Erstellung, Parametrisierung und Durchführung von Tests erscheint auf den ersten Blick sicherlich ungewöhnlich. Aber die Tests lassen sich ähnlich einfach entwickeln, wie in der xUnit-Familie. Die Durchführung eines Tests mit unterschiedlichen Parametern und erwarteten Ergebnissen sowie die übersichtliche Darstellung bilden eine Alternative, die einen näheren Blick auf das Werkzeug rechtfertigt. Die xUnit-Familie Das bei vielen eigentlich mit dem Test Driven Development verbundene Werkzeug ist xUnit. Das x ist hier zu ersetzen durch S, J, N, C, Cpp, Py, Ruby und weitere Buchstabenkombinationen. Diese stehen für Smalltalk, Java, .NET, C, C++, Python, Ruby und was die Sprachenwelt noch so zu bieten hat. So auch ABAP, Delphi oder SQL in der Form von Transact-SQL und PL/SQL. Vielfach wird Java mit JUnit der Startschuss für diese Entwicklung zugeschrieben. Doch Kent Beck entwickelte seine Idee für ein Muster und ein Framework zur automatisierten und programmgesteuerten Verifikation von Software-Modulen zuerst für Smalltalk [SUNIT]. Nichts desto trotz kam mit dem Erfolg von Java und der Portierung von SUnit nach JUnit erst der Durchbruch. SUnit ist für inzwischen für die Dialekte und Umgebungen VisualWorks, VisualAge Smalltalk, Dolphin, GemStone/S, Squeak, VisualSmalltalk und GNU Smalltalk verfügbar. Es hat sich bei der Entwicklung vieler offener Projekte etabliert, die ihren Quellen die notwendigen TestCases mitgeben, um die Funktionsfähigkeit nach der Integration in das Image zu verifizieren. Je nach Dialekt ist der graphische TestRunner hierfür in den Package Browser integriert, was sehr praktisch ist, steht in seiner Standardvariante eigenständig zur Verfügung, existiert in Komfortvarianten oder ist zur Not einfach im Workspace aufrufbar. In diesem Falle wird das Ergebnis im Transcript ausgegeben. Das Java-Framework JUnit hat ebenfalls eine sehr starke Verbreitung. Neben der allein stehenden Version ist es in die Entwicklungsumgebungen Eclipse, WSAD, IDEA, NetBeans, JBuilder, JDeveloper, TogetherJ, VisualAge Java und weiteren integriert. Durch die starke Beachtung in den Medien - und da kann sich auch dieser Artikel nicht von ausnehmen - sowie die große Verbreitung von Java gehören Unit Tests in diesem Umfeld inzwischen zum Alltag. Auch ohne streng den Prinzipien des Test Driven Development zu gehorchen, wird JUnit dennoch gerne verwandt, um einzelne Elemente ihrer Software isoliert testen zu können. Hier dient das Werkzeug mehr der Vereinfachung von Tests. Doch immer mehr Unternehmen erkennen den Wert automatisierter Tests, wie wir ihn bereits im letzten Artikel aufgeführt haben. In der .NET-Welt ist NUnit leider noch nicht von Seiten Microsoft aus in Visual Studio .NET integriert. Dieses Manko wird jedoch durch [NUNITADDIN], welches auf Sourceforge frei verfügbar ist, behoben. Eine Alternative zu NUnit, die ebenfalls frei verfügbar und in das Visual Studio integrierbar ist, ist csUnit [CSUNIT]. Für Visual Basic vor der .NET-Zeit gibt es noch ein eigenes Unit-Testing-Produkt namens vbUnit [VBUNIT]. Es liegt sowohl als freie als auch als kommerzielle Version vor. Während erstere nur einen Standalone TestRunner hat, ist die Profiversion in die IDE integriert. In den drei oben genannten Umfeldern hat sich das Unit Testing inzwischen zunehmen etabliert, nicht hinreichend, aber der Trend ist da. Eine Szene, die sich da leider noch von ausnimmt, ist die der doch sehr wichtigen C und C++ unter Unix. So ist doch ein Großteil der Tools und Applikationen für Unix in diesen beiden Sprachen geschrieben. Glücklicherweise gibt es hier mit [CHECK], [CUNIT] und [CPPUNIT] zwei Frameworks für C und eines für C++ zur Verfügung. Alle drei sind Open Source und ermöglichen es dem Entwickler auch in diesem Umfeld seine Software mit Unit Tests zu verifizieren. CppUnit orientiert sich dabei sehr stark an Kent Becks SUnit und JUnit, bietet neben einem textuellen TestRunner auch graphische auf Basis der wxWidgets Cross-Platform GUI Library. Letzteres deutet auch schon an, dass CppUnit auch unter Windows verfügbar ist. In der Tat können mit diesem Tool auch Visual-C++-Programme verifiziert werden. Für die genannten und alle weiteren Sprachen bieten Seiten wie [TESTDRIVEN], [OSTESTING] oder [TESTINGFW] viele Links und Informationen. Sie haben sich den verschiedenen Werkzeugen verschrieben und verwalten nach Sprachen sortiert die Verweise auf die Homepages dieser Programme. Erweiterungen Zu den genannten Werkzeugen existiert inzwischen auch eine Vielzahl von Erweiterungen. Diese setzen in der Regel auf dem Test-Framework, und hier überwiegend auf JUnit, auf. Diese Erweiterungen adressieren Tests, die nicht unmittelbar auf Code durchführbar sind. Ein Grund hierfür ist die Tatsache, dass der Code eine spezielle Laufzeitumgebung benötigt. So zum Beispiel J2EE. Während das originale JUnit sich auf reine Client- bzw. Stand-Alone-Applikationen konzentriert, sind Tests von J2EE-Komponenten nur mit einem nicht unerheblichen manuellen Aufwand möglich. Abhilfe schaffen hier Werkzeuge wie [!JUNITEE]. JUnitEE erleichtert über ein Framework und ein Servlet den Test von J2EE-Komponenten. Das Servlet dient als TestRunner für den Aufruf und die Visualisierung der Tests. Ein weiteres, immer wieder in den Tests komplexer Anwendungssysteme auftauchendes Problem ist der hohe Grad an Abhängigkeiten zwischen den Klassen. Insbesondere der Aufstieg von den Bestandteilen einfacher Frameworks, Hilfsklassen oder dem Modell zu den Geschäftskomponenten, die auf diesen Klassen aufbauen. Ein typisches Beispiel ist der Test von Komponenten, die ihrerseits wieder auf externe Systeme wie Datenbanksysteme oder LDAP-Server zurückgreifen müssen. Nun ist es erstens müßig, immer wieder mal unterschiedliche Server zu konfigurieren, zweitens auf diesen auch einen Zustand herzustellen, der für den Test notwendig ist, und drittens muss auch für die Verfügbarkeit gesorgt werden. Leider streiten sich in größeren Teams viele Entwickler um die gleichen Ressourcen. Abhilfe schaffen an dieser Stelle Mock-Objekte, also Attrappen, wie sie schon aus der Flugzeug- oder Automobilentwicklung bekannt sind. In der Software-Entwicklung bezeichnen Mocks Stellvertreterklassen, welche die gleichen Schnittstellen vorweisen, wie die Klassen, die sie vertreten. Jedoch ist in diesen Klassen die Logik inklusive der Daten hart codiert. Eine Datenbankabfrage gegen eine solche Stellvertreterkomponente gibt also immer den gleichen Wert oder eine geringe Menge abhängig von Parametern zurück. So schlägt der Test der nutzenden Komponente nicht fehl, nur weil mal das Backend nicht zur Verfügung steht oder jemand anderes im gleichen Test kurz zuvor die Testdaten verändert hat. Vielmehr kann sich der Tester auf eine Reproduzierbarkeit verlassen und seine Komponente isoliert verifizieren. Ob der nach einer Änderung der Datenbankschnittstelle, die durch einen eigenen Test geprüft wurde, auch noch das tatsächliche Zusammenspiel funktioniert, ist Bestandteil eines Integrationstests ohne Mock-Objekte. Zumindest an dieser Stelle. Nun ist es müßig, die notwendigen Klassen für Mock-Objekte zu 100 Prozent von Hand zu implementieren. Helfer hierfür sind Werkzeuge wie [MOCKCREATOR]. Dieses Werkzeug unterstützt sowohl die Generierung von Mock-Objekten auf Basis von Schnittstellen oder Klassen als auch deren Nutzung innerhalb der Tests. Damit werden Tests größerer Systeme stark vereinfacht. Gerade für JUnit existiert noch eine Vielzahl bisher nicht genannter Erweiterungen, die über das rein funktionale Testen hinausgehen. Kundenseitige Anforderungen umfassen vielfach auch nicht-funktionale Aspekte wie Die Anwendung soll schön schnell sein. Na ja, hoffen wir, dass die Anforderung schon etwas genauer formuliert ist. Zumindest sollte man darauf hinwirken. Sodann eine zeitliche präzisiere zeitliche Anforderung vorliegt, fällt es doch schwer, präzise Antwortzeiten mal eben von Hand zu stoppen oder dabei verlässliche Aussagen über das Skalierungsverhalten der Anwendung zu treffen. Hier helfen Werkzeuge wie [LOADUNIT], die komplexere Lasttests auf Komponentenebene durchführen. Der frühzeitige Einsatz dieser Art von Tests sorgt dafür, dass Anwendungen nicht am Ende noch aufwendig optimiert werden müssen. Vielmehr können Architekturentscheidungen oder Implementierungsdetails an kritischen Positionen frühzeitig in die richtige Richtung gelenkt werden. Eine spät festgestellte schlechte Skalierbarkeit auf Basis einer unzureichenden Architektur hat schon so manches Projekt in starken Verzug gebracht. Oberflächliches Eines der schwierigeren Kapitel in der Testautomatisierung ist die Verifikation von Benutzeroberflächen im Rahmen der Integrations- und Systemtests. Hier bieten sich zwei unterschiedliche Lösungswege an. Einer ist die Simulation von Events für die Anwendung. Das Tool [JFCUNIT] - erneut eine Erweiterung zu JUnit - hakt sich hier entweder in die Event Queue von Swing oder in die des Betriebssystems ein. So können Komponenten in Swing-Oberflächen lokalisiert und explizit für diese Events ausgelöst werden. Ein Testprogramm ahmt damit die Bedienung durch den Benutzer nach und prüft erwartete Reaktionen. Für einen Login-Dialog hat dies beispielsweise folgendes Aussehen: NamedComponentFinder finder = new NamedComponentFinder(JComponent.class, "LoginNameTextField" ); Gleichzeitig können auch Events aufgenommen und gespeichert werden. Dieses Feature erleichtert das Debugging. Neben der vielen kleinen freien Werkzeuge gibt es natürlich auch noch die großen kommerziellen, wie den IBM Rational Test Manager, den Telelogic TAU/Tester oder Computer Associates AllFusion Test-Produkte. Diese sind in der Regel sehr umfangreich, bieten eine Integration in die weiteren Entwicklungswerkzeuge und decken mehr als nur reine Funktionstests ab. Dafür haben sie jedoch auch ihren Preis. Auch HTML-Seiten unterliegen Anforderungen, neben Antwortzeiten auch an W3C-Konformität oder Aspekten wie der Bedienbarkeit durch Besucher mit körperlichen Einschränkungen. So kann der Besuch einer Website bei Farbblindheit durch ungünstige Farbkombinationen stark behindert werden. Für Tests derartiger Aspekte existiert eine Vielzahl von Seiten, die eine URL checken. Doch statt sich diese einzeln zu suchen, hilft der Besuch von [UITEST], wo der Anbieter der Seite diese Tests komfortabel und gut gruppiert zusammengefasst hat. Nach Angabe des zu testenden URL stehen die angepassten Links mit den Aufrufen der Tests zur Verfügung. Nun kann der Webentwickler diese nacheinander auswählen und bekommt das Ergebnis der Überprüfung präsentiert. Einzige Voraussetzung ist die Erreichbarkeit der Seite von außen. Qualitätssteigerung Was helfen die schönsten Unit Tests mit hervorragenden grünen Balken, wenn sie ein falsches Bild wiedergeben? Ein falsches Bild, bei den so gelobten Unit Tests? Wie das? Das geschieht ganz einfach. Man kann sowohl das falsche bzw. nicht ausreichend testen. Und man kann falsch testen. Für die Lösung des ersten Problems steht noch technische Unterstützung bereit. Werkzeuge wie [CLOVER] prüfen die Code-Abdeckung durch Tests und geben dieses in Form von HTML-Reports, Integration in Entwicklungsumgebungen, Langzeitreports via PDF oder in einem eigenen Coverage-Browser wieder. Die kontinuierliche Prüfung der Abdeckung zeigt der Qualitätssicherung, in welche Richtung noch Testaufwände zu lenken sind oder für welche Bereiche bei der Erweiterung der Code-Basis die Unit Tests nicht mehr nachgezogen werden. Clover ist für Java und .NET verfügbar. Falsches Testen zu verhindern ist etwas schwieriger. Anfangs ist viel Euphorie für die Idee des Test Driven Development oder des Test-First-Ansatzes aus dem eXtreme-Programming vorhanden. Jedoch zerbricht diese Euphorie sowohl an den Schwierigkeiten des Unit Testings als auch am Projektalltag. Letztendlich haben sehr viele alteingesessene Entwickler doch eine kritische Haltung zum Testen. Doch der Reihe nach. Die Beispiele in der Literatur sind vielfach sehr einfache. Diese haben zwar den Vorteil, dass sie einfach nachvollziehbar sind und somit den Einstieg erleichtern. Doch der Nachweis nicht trivialer Funktionalitäten in komplexen Komponenten oder Umgebungen fällt nicht so leicht. Der kurze Ausflug zum Thema Mock-Objekte zeigte bereits eine der Problematiken und einen Lösungsansatz. Hier ist es wichtig, sich jederzeit klar zu sein, was genau getestet werden soll. Also sowohl, welcher fachliche Aspekt als auch welche Komponente. Bei letzterer ist es insbesondere wichtig zu wissen, welche Komponenten denn nicht zu testen sind, damit diese ausgegrenzt bzw. durch Mock-Objekte ersetzt werden können. So werden durch den richtigen Testansatz, also mit einer sorgsam aufgebauten Umgebung sowie Stellvertretern an den richtigen Stellen, Seiteneffekte vermieden und die Präzision des Tests gesteigert. Innerhalb der Komponenten muss man sich weiterhin des Protokolls sicher sein, mit dem eine Klasse genutzt werden soll. Tests, die diese Protokolle falsch abdecken, sind ebenso wenig hilfreich, wie Tests, die nicht alle tatsächlich im Einsatz befindlichen Protokolle abdecken. Für die Abdeckung des Codes an sich helfen, wie bereits genannt, Werkzeuge wie Clover. Doch die Sicherstellung der Einhaltung von Protokollen ist ein manueller Prozess, individuell pro Komponente abzuleisten und im Sinne der Wartung gut zu dokumentieren. Hier zeigt sich übrigens der Vorteil von Unit Tests als Dokumentation einer API in stark Code-zentrierten Systemen. Die einzelnen Tests selbst lassen ebenfalls leicht eine falsche Teststrategie zu. Tests offensichtlicher Eigenschaften mit einem zu stark begrenzten Wertebereich sind vielfach wenig hilfreich. Zusätzliche Tests mit Extrema helfen oftmals eher, Schwachstellen zu entdecken. Bei numerischen Funktionen beispielsweise mit dem Minimalwert, Null und dem Maximalwert des oder der Parameter. Hier treten oftmals interessante Effekte zu Tage. Bei Zeichenketten sind es hingegen vielfach die Längen, die ruhig mal missachtet werden sollten, oder generell die Übergabe von Null-Werten. Das Verhalten einer Komponente im Fehlerfall gehört ebenso um Protokoll wie damit auch der Test dieses Verhaltens notwendig ist. Diese Beispiele zeigen, dass eine Einführung eines Unit Testings nicht leichtfertig vorzunehmen ist. Mit dem einfachen Statement Ab heute machen wir Unit Tests ist es nicht getan. Der Prozess muss in Ruhe vorbereitet sein und startet optimalerweise mit einem frischen Projekt, da Tests vielfach nur schwer in bestehendem Code zu integrieren sind. Erfahrene Entwickler sollten ihre Teammitglieder trainieren und bei der Arbeit begleiten dürfen. Gemeinsame Workshops helfen bei der Entwicklung eines übergreifenden Verständnisses und beim Aufbau einer Testkultur. Mit den Ansprüchen durch das Projekt wachsen so auch die Fähigkeiten des Teams, Testen wird nach und nach zur Selbstverständlichkeit und integraler Bestandteil des Prozesses. Die steigenden Ansprüche durch das Projekt bilden für die Entwickler einen kontinuierlichen Anreiz und wirken einem abflauenden Interesse entgegen. Sich einschleichenden Inkonsequenzen muss sofort gegengesteuert werden. Konsequentes Monitoring durch die Qualitätssicherung oder die technische Leitung deckt dieses auf, so dass kurzfristig die bereits oben aufgeführten Maßnahmen verstärkt werden können. Dabei ist es wichtig, eine Begeisterung sowie den Stolz auf die Entwicklung eines Qualitätsprodukts aufzubauen. Fazit Für eine stabile und qualitativ hochwertige Software gelten auch heute noch die Regeln, die das amerikanische Magazin Byte bereits 1995 formulierte:
Mit dem Test Driven Development wird insbesondere der letzte Aspekt hervorgehoben. Dennoch gelten die Regeln der Byte auch heute noch. Wem eine qualitativ hochwertige Software lieb ist, der muss zu einer Anfangsinvestition bereit sein. Doch diese zahlt sich ebenso wie die Etablierung eines durchgängigen Testens aus. Wie bereits im ersten Teil gezeigt, senken sich auf diesem Wege die Kosten für die Fertigstellung und die Wartung. Die sich hierbei aufzeigenden Schwierigkeiten und Widerstände in der Lernphase können und müssen dafür überwunden werden. Der Markt dankt es mit einem guten Ruf. Olga Kolov arbeitet als Software-Qualitäts-Beauftragte bei der BOSS AG in Bremen. Frank Müller arbeitet als Systemspezialist bei der THALES Defence Deutschland GmbH in Wilhelmshaven. Links [FIT] fit.c2.com [SUNIT] www.xprogramming.com/testfram.htm [NUNITADDIN] http://sourceforge.net/projects/nunitaddin/ [CSUNIT] www.csunit.org [VBUNIT] www.vbunit.org [CHECK] check.sourceforge.net [CUNIT] cunit.sourceforge.net [CPPUNIT] cppunit.sourceforge.net [TESTDRIVEN] www.testdriven.com [TESTINGFW] c2.com/cgi/wiki?TestingFramework [OSTESTING] www.opensourcetesting.org [JUNITEE] www.junitee.org [MOCKCREATOR] mockcreator.sourceforge.net [LOADUNIT] loadunit.sourceforge.net [JFCUNIT] jfcunit.sourceforge.net [UITEST] uitest.com/en/check/ [CLOVER] www.cenqua.com/clover/ |
||
|