Codeabdeckung und andere Aspekte von Komponententests (Teil 2)
Kommentare

Letztlich ist Codeabdeckung eine Zahl, die vom konkreten Messverfahren abhängig ist. Was wirklich zählt, ist die Relevanz von Tests. Blindlings die Codeabdeckung zu steigern oder, was noch schlimmer

Letztlich ist Codeabdeckung eine Zahl, die vom konkreten Messverfahren abhängig ist. Was wirklich zählt, ist die Relevanz von Tests. Blindlings die Codeabdeckung zu steigern oder, was noch schlimmer ist, zu verlangen, dass Entwickler irgendwie eine festgelegte Schwelle der Abdeckung erreichen, bietet für gar nichts eine Gewähr. Das ist sicher noch besser, als überhaupt keine Tests auszuführen, doch es sagt nichts über die Relevanz und Effizienz der Tests aus. Die vernünftigsten Testkonzepte konzentrieren sich auf das erwartete Verhalten und die Eingaben. Eine gut getestete Anwendung ist eine Anwendung, die eine hohe Codeabdeckung von relevanten Szenarios vorweisen kann.

Ein wenig Hilfe, um die Relevanz von Komponententests anzuheben

Einfache Komponententests lassen sich möglicherweise mechanisch generieren; relevante Tests setzten ein profundes Verständnis des Kontexts und der Anwendung voraus. Mit anderen Worten ist ein Komponententest eine Whitebox-Form des Testens. Von den Testern wird nämlich erwartet, jede Menge Details über die Interna des zu testenden Codes zu kennen. Automatisch vom Menschen oder per Software generierter Testcode entsteht, indem eine statische Menge von Regeln angewandt wird. Für mich sieht das eher wie eine Art Blackboxtesten in einem Whiteboxkontext aus. Pex von Microsoft ist ein Add-in für Visual Studio 2010, das die Generierung von relevanten Tests, die Sie benötigen, ein wenig automatisieren kann. Herunterladen können Sie Pex unter http://goo.gl/yYZj. Intern greift Pex auf statische Analyseverfahren zurück, um Wissen über das Verhalten Ihrer Anwendung zu erstellen. Prinzipiell führt Pex eine gründliche Analyse Ihres Codes aus und sucht dabei nach Grenzbedingungen und Ausnahmen. Dabei baut das Programm eine Wissensbasis des Codes auf, indem nach Anweisungen für Codeverträge und Assertions gesucht wird. Je mehr Assertions Pex im Verlauf des Tests findet, desto zuverlässiger ist die Ausgabemenge der Tests. Findet Pex eine Assertion, versucht es systematisch, sie zum Scheitern zu bringen. Dazu generiert das Programm parametrisierte Tests und realisiert somit eine hundertprozentige Codeabdeckung. Wie bereits erwähnt, ist eine hundertprozentige Codeabdeckung nicht unbedingt eine gute Aussage, sicher ist aber, dass ein geringes Niveau der Codeabdeckung zweifellos eine schlechte Aussage ist.

Testen in Isolation

Ein weiterer wichtiger Aspekt eines Komponententests ist seine Ausführung in Isolation. Wenn Sie eine Methode testen, möchten Sie sich ausschließlich auf den Code innerhalb dieser Methode konzentrieren. Denn Sie wollen lediglich wissen, ob dieser Code in den gestesteten Szenarios die erwarteten Ergebnisse bringt. Zu diesem Zweck müssen Sie alle Abhängigkeiten loswerden, die diese Methode eventuell aufweist. Ruft die Methode beispielsweise eine andere Klasse auf, nehmen Sie an, dass die aufgerufene Klasse immer korrekte Ergebnisse zurückgibt. Auf diese Weise beseitigen Sie bereits an der Wurzel das Risiko, dass die Methode unter dem Test scheitert, weil ein Fehler weiter unten im Aufruf-Stack aufgetreten ist. Wenn Sie Methode A testen und diese scheitert, müssen Sie den Grund dafür ausschließlich im Quellcode der Methode A suchen und nicht in irgendwelchen Abhängigkeiten.

Die zu testende Klasse sollten Sie unbedingt von ihren Abhängigkeiten isolieren. Allerdings lässt sich das nur erreichen, wenn die Klasse in lose gekoppelter Manier entworfen wurde. In einem objektorientierten Szenario hängt Klasse A von Klasse B ab, wenn zwischen den beiden Klassen eine klare Vererbungsbeziehung besteht. Außerdem haben Sie es mit einer Abhängigkeit zu tun, wenn Klasse A einen Member der Klasse B einbindet oder wenn eine der Methoden von Klasse A eine Methode der Klasse B aufruft. Analog gibt es eine Abhängigkeit, wenn eine der Methoden von Klasse A einen Parameter der Klasse B übernimmt oder zurückgibt und wenn Klasse A von einer Klasse abhängig ist, die ihrerseits von B abhängt.

Um Abhängigkeiten beim Testen einer Methode zu kompensieren, greifen Sie auf Testdoubles zurück. Ein Testdouble ist ein Objekt, das Sie anstelle eines anderen verwenden. Es gibt vor, das wirkliche Objekt zu sein, das in einem bestimmten Szenario erwartet wird. Eine andere Möglichkeit ist die Verwendung von Fakeobjekten. Dabei handelt es sich um einen einfachen Klon eines Objekts, der die gleiche Schnittstelle wie das Originalobjekt bereitstellt, jedoch fest kodierte oder per Programm bestimmte Werte zurückgibt. Schließlich können Sie Mock-Objekte heranziehen. Ein Mock ist ein dynamisches Objekt, das auf einem spezifischen Framework aufsetzt und sich deklarativ programmieren lässt, um für eine bestimmte Eingabe eine festgelegte Ausgabe zurückzuliefern.

Zusammenfassung

Tests für die gesamte Codebasis zu haben, kann für Ihre Anwendung eine großartige Neuigkeit sein oder auch nicht. Das hängt alles von der Relevanz der verfügbaren Tests ab. Pex ist ein Add-in für Visual Studio, mit dem sich Tests für hundertprozentige Codeabdeckung und parametrisierte Tests zum Teil automatisch erstellen lassen. Die Abdeckung aller Pfade bringt nur etwas, wenn Sie Objekte frei von ihren Abhängigkeiten testen. Um das zu ermöglichen, müssen Sie die Klassen zweckmäßig konzipieren und Testdoubles im Test verwenden. Wenn Sie diese beiden Aspekte des Testens beherzigen, wird die Testdurchführung sogar zu einer angenehmen Aufgabe werden und besonders effektiv sein.

Dino Esposito ist CTO bei e-tennis.NET, einer Firma, die sich auf webbasierte und mobile Lösungen für Sportereignisse in ganz Europa spezialisiert hat (http://www.e-tennis.net). Außerdem ist Dino der Autor von „Programming ASP.NET MVC3“, Microsoft Press, 2011.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -