2010-11-18 18 views
6

Ich habe gelesen, dass statische Methoden vermieden werden, wenn TDD verwendet wird, weil sie schwer zu verspotten sind. Ich finde jedoch, dass es am einfachsten ist, eine statische Methode mit einfacher Funktionalität zu testen. Sie müssen keine Klassen instanziieren, Methoden ermutigen, die einfach sind, eine Sache machen, "alleine" sind usw.statische Methoden und Komponententests

Kann jemand diese Diskrepanz zwischen TDD Best Practices und pragmatischer Leichtigkeit erklären?

Dank, A

Antwort

14

Eine statische Methode ist einfach zu testen, aber etwas, das direkt im Allgemeinen eine statische Methode nennt, ist nicht einfach, unabhängig von der statischen Methode zu testen, es hängt davon ab. Mit einer nicht statischen Methode können Sie eine Stub/Mock/Fake-Instanz verwenden, um das Testen zu erleichtern. Wenn der zu testende Code jedoch statische Methoden aufruft, ist er effektiv mit dieser statischen Methode "fest verdrahtet".

+0

Ich denke, der Begriff, den Sie suchen denn ist eng gekoppelt. –

+1

@Martin: Danke, ich kenne den Begriff, obwohl es allgemeiner ist als das, woran ich hier herankomme. Häufig verwendete Begriffe verlieren oft ihre Bedeutung, weil sie von den Menschen so oft benutzt werden. Deshalb habe ich mich hier für eine Metapher entschieden, in der Hoffnung, dass es klarer wäre. –

+0

Erstes Hören "fest verdrahtet" anstelle von fest verbunden. Es ist absolut genial, wie ein Wechsel in Begriffen zum Verständnis beitragen kann. – jrahhali

2

Es ist einfach, die statische Methode zu testen. Das Problem besteht darin, dass es beim Testen des anderen Codes keine Möglichkeit gibt, den anderen Code von dieser statischen Methode zu isolieren. Der aufrufende Code ist eng mit dem statischen Code gekoppelt.

Ein Verweis auf eine statische Methode kann nicht von vielen spöttischen Frameworks verspottet werden, noch kann er überschrieben werden.

Wenn Sie eine Klasse haben, die viele statische Aufrufe durchführt, müssen Sie den globalen Status der Anwendung für alle diese statischen Aufrufe konfigurieren, damit die Wartung zum Albtraum wird. Und wenn Ihr Test fehlschlägt, dann wissen Sie nicht, welches Bit des Codes den Fehler verursacht hat.

Das falsch zu verstehen, ist einer der Gründe, warum viele Entwickler TDD für Unsinn halten. Sie haben einen großen Wartungsaufwand für Testergebnisse, die nur vage anzeigen, was schief gelaufen ist. Wenn sie nur die Kopplung zwischen ihren Codeeinheiten reduziert hätten, wäre die Wartung trivial und die Testergebnisse spezifisch.

3

Die Antwort auf die gestellte Frage ist meiner Meinung nach "Object Oriented" scheint alles zu sein, worüber TDD Leute nachdenken. "

Warum? Ich weiß es nicht. Vielleicht sind sie alle Java-Programmierer, die sich mit der Krankheit angesteckt haben, alles auf sechs Indirektionsschichten, Abhängigkeitsinjektion und Schnittstellenadapter angewiesen zu machen.

Java-Programmierer scheinen es zu lieben, alles im Voraus schwierig zu machen, um "später Zeit zu sparen".

Ich rate, einige Agile Prinzipien auf Ihre TDD anzuwenden: Wenn es kein Problem verursacht, dann reparieren Sie es nicht. Nicht über Design.

In der Praxis finde ich, dass, wenn die statischen Methoden zuerst gut getestet werden, sie nicht die Ursache von Fehlern in ihren Anrufern sein werden.

Wenn die statischen Methoden schnell ausgeführt werden, benötigen sie keinen Mock.

Wenn die statischen Methoden mit Dateien außerhalb des Programms arbeiten, benötigen Sie möglicherweise eine Scheinmethode. In diesem Fall müssten Sie in der Lage sein, viele verschiedene Arten von Funktionsverhalten zu simulieren.

Wenn Sie eine statische Methode verspotten müssen, denken Sie daran, dass es Möglichkeiten gibt, außerhalb der OO-Programmierung zu tun.

Zum Beispiel können Sie Skripte schreiben, um Ihren Quellcode in einem Testformular zu verarbeiten, das Ihre Mock-Funktion aufruft.Sie können verschiedene Objektdateien mit unterschiedlichen Versionen der Funktion in die Testprogramme einbinden. Sie könnten Linkertricks verwenden, um die Funktionsdefinition zu überschreiben (wenn sie nicht inline wurde). Ich bin mir sicher, dass es noch ein paar Tricks gibt, die ich hier nicht aufgelistet habe.

+0

Ich würde Ihnen in den einfachen Fällen zustimmen. Viele statische Methoden sind einfache Dienstprogrammaufrufe, die statisch sind, weil sie keinen Status haben. Andere statische Aufrufe verweisen jedoch auf globale (statische) Variablen oder andere statische Aufrufe, und dies kann in einer Komponententestumgebung sehr schwierig zu verwalten sein. Sie müssen sicherstellen, dass der globale Status für jeden Testlauf korrekt ist - andernfalls erhalten Sie Flockigkeit (Tests, die isoliert ausgeführt werden, aber fehlschlagen, wenn der Rest der Suite ausgeführt wird). Es kann also ein Würmer sein, aber ich stimme dir zu, dass du pragmatisch sein solltest. – sheikhjabootie

0

Dieser Rat ist in den meisten Fällen wahr .. aber nicht immer. Meine Kommentare sind nicht C++ spezifische ..

  1. Schreiben von Tests für statische Methoden (die rein/staatenlos Funktionen): das heißt, die Arbeit aus den Eingängen ein konsistentes Ergebnis zu erzeugen. z.B. Add follow - gibt immer den gleichen Wert für einen bestimmten Satz von Eingängen. Es gibt kein Problem schriftlich Tests für diese oder Code, der solche reinen statischen Methoden aufruft.
  2. Schreiben Tests für statische Methoden, die verbrauchen statischen Zustand: z.B. GetAddCount() unten. Der Aufruf in mehreren Tests kann unterschiedliche Werte ergeben. Daher kann ein Test möglicherweise die Ausführung eines anderen Tests beeinträchtigen - Tests müssen unabhängig sein. Also müssen wir jetzt eine Methode einführen, um den statischen Zustand zurückzusetzen, so dass jeder Test von einem sauberen Slate starten kann (z.B. etwas wie ResetCount()).
  3. Schreiben von Tests für Code, der auf statische Methoden zugreift aber kein Quellcodezugriff auf die Abhängigkeit: Erneut hängt von den Eigenschaften der statischen Methoden selbst ab. Wenn sie jedoch knorrig sind, haben Sie eine schwierige Abhängigkeit. Wenn die Abhängigkeit ein Objekt ist, können Sie dem abhängigen Typ einen Setter hinzufügen und ein falsches Objekt für Ihre Tests setzen/injizieren. Wenn die Abhängigkeit statisch ist, benötigen Sie möglicherweise ein umfangreiches Refactoring, bevor Sie Tests zuverlässig ausführen können. (ZB Hinzufügen eines Objekts Mitte-Mann Abhängigkeit, die Delegierten der statischen Methode. Jetzt Plugin eine gefälschte Mitte-Mann für Ihre Tests)

Lets Nehmen wir ein Beispiel

public class MyStaticClass 
{ 
    static int __count = 0; 
    public static int GetAddCount() 
    { return ++__count; } 

    public static int Add(int operand1, int operand2) 
    { return operand1 + operand2; } 

    // needed for testability 
    internal static void ResetCount() 
    { 
    __count = 0; 
    } 
} 

... 

//test1 
MyStaticClass.Add(2,3);  // => 5 
MyStaticClass.GetAddCount(); // => 1 

// test2 
MyStaticClass.Add(2,3); // => 5 
//MyStaticClass.ResetCount(); // needed for tests 
MyStaticClass.GetAddCount(); // => unless Reset is done, it can differ from 1