Modultest

aus Wikipedia, der freien Enzyklopädie
(Weitergeleitet von Unit Tests)
Wechseln zu: Navigation, Suche
QS-Informatik

Dieser Artikel wurde aufgrund von inhaltlichen Mängeln auf der Qualitätssicherungsseite der Redaktion Informatik eingetragen. Dies geschieht, um die Qualität der Artikel aus dem Themengebiet Informatik auf ein akzeptables Niveau zu bringen. Hilf mit, die inhaltlichen Mängel dieses Artikels zu beseitigen, und beteilige dich an der Diskussion! (+)

Dieser Artikel oder Abschnitt bedarf einer Überarbeitung. Näheres ist auf der Diskussionsseite angegeben. Hilf mit, ihn zu verbessern, und entferne anschließend diese Markierung.

In der Softwareentwicklung wird ein Computerprogramm üblicherweise in einzelne Teile mit klar definierten Schnittstellen, sogenannte Module, unterteilt. Der Modultest (auch Komponententest oder oft vom engl. unit test als Unittest bezeichnet) ist der Softwaretest dieser Programmteile, die zu einem späteren Zeitpunkt zusammengefügt (integriert) werden (vgl. Integrationstest). Ziel des Modultests ist es, frühzeitig Programmfehler in den Modulen einer Software (z. B. von einzelnen Klassen) zu finden. Die Funktionalität der Module kann so meist einfacher getestet werden, als wenn die Module bereits integriert sind, da in diesem Fall die Abhängigkeit der Einzelmodule mit in Betracht gezogen werden muss.

Inhaltsverzeichnis

[Bearbeiten] Automatisierte Modultests

Mit der Verbreitung von agilen Softwareentwicklungsmethoden und insbesondere testgetriebener Entwicklung hat sich die Ansicht verbreitet, Modultests ausschließlich automatisiert durchzuführen. Dazu werden üblicherweise mit Hilfe sogenannter Test Frameworks wie beispielsweise JUnit Testprogramme geschrieben, welche die zu testenden Module, in der Regel etwa eine Methode oder eine Funktion, aufrufen und auf korrekte Funktionsweise testen.

Die automatisierten Modultests haben den Vorteil, dass sie rasch und von jedermann ausgeführt werden können. Somit besteht die Möglichkeit, nach jeder Programmänderung durch Ablauf aller Modultests nach Programmfehlern zu suchen. Dies wird üblicherweise empfohlen, da damit etwaige neu entstandene Fehler schnell entdeckt und somit kostengünstig behoben werden können. Dies setzt allerdings voraus, dass die Modultests vor Programmänderungen 100% durchlaufen, also Entwickler nur dann ihren Sourcecode einchecken, wenn alle Modultests erfolgreich durchlaufen.

[Bearbeiten] Eigenschaften von Modultests

Isoliert
Modultests testen die Module isoliert, d. h. ohne die Interaktion der Module mit anderen. Ist das nicht der Fall spricht man nicht von Modultests, sondern von Integrationstests. Dazu müssen andere Module beziehungsweise externe Komponenten wie etwa eine Datenbank, Dateien oder Backendsysteme, die von dem Modul verwendet werden, simuliert (engl. to mock) werden. Diese Module nennt man Mock-Objekte. Auch dafür verwendet man üblicherweise Frameworks wie beispielsweise Easymock.
Test von Fehlverhalten
Modultests testen ausdrücklich nicht nur das Verhalten des Moduls im Gutfall, beispielsweise bei korrekten Eingabewerten, sondern auch im Fehlerfall, beispielsweise bei unkorrekten Eingabewerten oder von anderen Modulen gelieferten Fehlermeldungen. Auch dafür ist das Mocken anderer Module hilfreich, da sich ein Fehlzustand anderer Module, wie beispielsweise der Verbindungsabbruch bei Netzwerkverbindungen, durch Mock-Objekte leichter simulieren als in der Realität nachstellen lässt.
Laufende Ausführung
Modultests sollten im Laufe der Entwicklung regelmäßig durchgeführt werden, um zu verifizieren, dass Änderungen keine unerwünschten Nebeneffekte haben. Modultests sollten daher von jedem Entwickler vor dem Einchecken durchgeführt werden, automatisierte Modultests auch bei Kontinuierlicher Integration auf sogenannten Continuous Integration Servern wie beispielsweise Jenkins.
Test des Vertrages und nicht der Algorithmen
Modultests sollen gemäß dem Design-by-contract-Prinzip möglichst nicht die Interna einer Methode testen, sondern nur ihre externen Auswirkungen (Rückgabewerte, Ausgaben, Zustandsänderungen, Zusicherungen). Werden auch interne Details der Methode geprüft (dies wird als White-Box-Testing bezeichnet), droht der Test fragil zu werden, er könnte auch 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.
Testgetriebene Entwicklung
Bei der Testgetriebenen Entwicklung (TDD von Test driven development) wird jeweils ein Modultest vor dem Erstellen bzw. Ändern des eigentlichen Programmcodes erstellt und gepflegt. Dies hat verschiedene Vorteile: Es wird verifiziert, dass der Test ohne die Änderung wirklich fehlschlägt, es reduziert die Gefahr des übermäßigen White-Box-Testings, es verbessert das Design, da sich der Entwickler so besser über das benötigte Verhalten der Methode klar werden kann, bevor er mit der Entwicklung beginnt. Darum ist es in der Praxis meist weniger aufwendig einen Test vor der Implementierung zu schreiben als umgekehrt.
Pro Bug ein Test
Die Erstellung eines Modultests vor Behebung eines Fehlers bietet einige Möglichkeiten. Einerseits stellt der Test sicher, dass der Bug wirklich in dem Programmcode vorhanden ist, wo man ihn auszubessern gedenkt, andererseits dass der Bug auch durch die Programmänderung tatsächlich behoben wurde und auch in Zukunft nicht mehr auftreten kann. Einige Open-Source-Projekte fordern daher, dass bei Fehlern des Programms nicht nur ein Fix, sondern auch ein Test mitgeliefert wird, der ohne den Fix fehlschlägt, aber mit dem Fix korrekt abläuft.

Modultests sind die Vorstufe zu Integrationstests, die wiederum zum Testen mehrerer voneinander abhängiger Komponenten im Zusammenspiel geeignet sind. Im Gegensatz zu Modultests werden Integrationstests meist manuell ausgeführt.

[Bearbeiten] Anwendungsbeispiele

Modultests werden auch im Automotive-Bereich an programmierbaren Steuereinheiten verwendet. Damit wird die Steuereinheit verifiziert (ihre Übereinstimmung mit der Absicht des Entwicklers geprüft). Hier haben die Modultests auch rechtliche Bedeutung innerhalb des Vertragsdokumentes. Falls eine programmierbare Steuerung versagt, kann es zu Personenschäden kommen. Bei einem solchen Test wird die Durchführung einschließlich aufgetretener Fehler protokollartig festgehalten. Dabei wird dann zwischen Unit-Test (kann der Test einer einzelnen C-Funktion sein) und Modultest (Test des gesamten Moduls, dazu gehören Tests der Units und Tests der Funktionsschnittstellen zwischen den Units) unterschieden. Im Automotive-Bereich stehen bei diesen Tests weniger textuelle Daten als vielmehr Variablen physikalischer Werte und damit Grenzwerte im Vordergrund. So muss z. B. geprüft werden, ob das Ergebnis einer Addition von Ganzzahlen sich in jedem Fall innerhalb des Wertebereiches des Ganzzahl-Datentyps befindet. Man erhält dabei über die Code-Abdeckung hinaus große Mengen an Zahlenlisten, die zu testen sind.

Bei Fluxtests werden die Datenflüsse der Schnittstellen integrierter Systeme abgehört und dem Regressionset für die Unittests beigefügt, da ja sowohl Input als auch Output bekannt ist. Die eigentliche Fluxtestphase erfolgt dabei erst beim nächsten Zyklus der Softwareentwicklung, in der den Units dann die bekannten Aufrufparameter übergeben werden beziehungsweise anhand der bekannten gewünschten Ausgabedaten die Units auf ihre Richtigkeit überprüft werden. Fluxtests können nur aus funktionierenden (teil-)integrierten Systemen gewonnen werden. Damit wird im nächsten Zyklus der Integration vorgegriffen. Bereits fertiggestellte Units werden früher getestet, der Release- oder Entwicklungszyklus verkürzt sich. Besonders bei "hardest-first" Integrationsstrategien zahlen sich Fluxtests somit aus.

[Bearbeiten] Beispieltest

Das folgende Beispiel ist eine Testsuite für eine Model-Klasse einer Ruby on Rails-Anwendung mit dem Shoulda-Test-Framework. Zunächst wird ein einfacher Test für Verknüpfungen zu anderen Objekten (hier Übersetzungen) geprüft. Mit einer setup-Methode wird ein Ort in die Datenbank eingetragen, anhand dessen dann zwei Methoden der Klasse mit unterschiedlichen Werten geprüft werden. Anhand der verschachtelten context- und should-Blöcke generiert Shoulda Methoden mit Namen wie Given I have a place name should return "Schweiz" for Switzerland in German oder Given I have a place name_with_local should return "Switzerland (Schweiz)" or "Switzerland (Suisse)" for Switzerland in English. I18n.locale setzt dabei die Spracheinstellung, während assert_equal und assert_contains die Methode aufrufen und den Rückgabewert mit den erwarteten Werten vergleichen.

class PlaceTest < ActiveRecord::TestCase
  should_have_many :translations
 
  context "Given I have a place" do
    setup do
      @Switzerland = Place.create!
      @Switzerland.translations.create! :name => "Schweiz", :locale => "de", :is_local => true
      @Switzerland.translations.create! :name => "Switzerland", :locale => "en"
      @Switzerland.translations.create! :name => "Suisse", :locale => "fr", :is_local => true
    end
 
    context "name" do
      should "return \"Schweiz\" for Switzerland in German" do
        I18n.locale = :de
        assert_equal "Schweiz", @Switzerland.name
      end
 
      should "return \"Switzerland\" for Switzerland in English" do
        I18n.locale = :en
        assert_equal "Switzerland", @Switzerland.name
      end
 
      should "return \"Switzerland\" for Switzerland in Korean" do
        I18n.locale = :ko
        assert_equal "Switzerland", @Switzerland.name
      end
    end
 
    context "name_with_local" do
      should "return \"Schweiz\" for Switzerland in German" do
        I18n.locale = :de
        assert_equal "Schweiz", @Switzerland.name_with_local
      end
 
      should "return \"Switzerland (Schweiz)\" or \"Switzerland (Suisse)\" for Switzerland in English" do
        I18n.locale = :en
        assert_contains ["Switzerland (Schweiz)", "Switzerland (Suisse)"], @Switzerland.name_with_local
      end
    end
  end
end

[Bearbeiten] Kritik

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 soviel getestet wird, dass alle Tests „grün“ sind. Module die keine fehlschlagenden Modultests haben als fehlerfrei zu behandeln ist ein häufiges Anti-Pattern in der Praxis testgetriebener Entwicklung.

Bei der Änderung von Code stellen Modultests sicher dass keine solchen Fehler unbemerkt eingefügt werden, die der vorhandene Bestand an Tests sicher aufdeckt. Das Problem, eine ausreichende Testabdeckung herzustellen, kann nur durch entsprechende Beachtung und geeignete Maßnahmen gelöst werden.

Wenn wie üblicherweise 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.

[Bearbeiten] Siehe auch

[Bearbeiten] Literatur

[Bearbeiten] Weblinks

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Mitmachen
Drucken/exportieren
Werkzeuge
In anderen Sprachen