2010-10-19 3 views
8

Ich bin neu zu TDD und DDD und ich habe eine einfache Frage zu statischen Methoden im Allgemeinen. Die meisten TDD-Gurus sagen mit einem Wort, dass statische Methoden schlecht sind (und dass wir vergessen sollten, Tonnen von statischen Dienstprogrammen zu erzeugen, die wir (um oder ich) früher benutzt haben, da sie nicht überprüfbar sind. Ich kann sehen, warum sie sind) nicht überprüfbar (ein großer Klärungsartikel kann gefunden werden here für diejenigen, die interessiert sind, aber ich denke, ich bin der einzige noob hier :(), aber ich frage mich, gibt es eine schöne und saubere Richtlinie für die Verwendung von Statik aus TDD Sicht?Statische Methoden: Wann und wenn nicht

Das mag für die meisten von euch eine wirklich dumme Frage sein, aber ein paar Tipps wären großartig und ich möchte nur wissen, wie Experten hier über statische Sachen denken. Danke im Voraus.

Edit: Während ich nach Antwort suchte, fand ich 2 andere nette Threads in Bezug auf die Verwendung von statischen (nicht TDD Bedenken), die ich raten sind gute reads für diejenigen, die interessiert sind (mich inklusive).

Antwort

11

Ich glaube, du etwas falsch verstanden haben.

Statische Methoden sind testbar. Nehmen Sie diese Methode als Beispiel:

public static int Add(int x, int y) 
{ 
    return x + y; 
} 

Sie diesen Test kann durch Testen, dass der Rückgabewert ist, was man auf der Grundlage der Argumente erwarten bestanden in

Wo statische Methoden lästig werden, wenn Tests ist, wenn Sie benötigen. einen Spott einführen.

Nehmen wir an, ich habe einen Code, der die statische Methode File.Delete() aufruft. Um meinen Code zu testen, ohne mich auf das Dateisystem zu verlassen, möchte ich diesen Aufruf durch eine Testversion ersetzen/nachahmen, die lediglich bestätigt, dass sie aus dem getesteten Code aufgerufen wurde. Das ist leicht zu tun, wenn ich eine Instanz eines Objekts hatte, auf dem Delete() aufgerufen wurde. Die meisten (alle?) Spionage-Frameworks können statische Methoden nicht vortäuschen, also zwingt mich eine statische Methode in meinem Code dazu, sie anders zu testen (normalerweise durch Aufruf der echten statischen Methode).

so etwas wie dies zu testen, würde ich eine Schnittstelle vorstellen:

interface IFileDeleter 
{ 
    void Delete(string file); 
} 

Mein Code würde eine Instanz eines Objekts dann nehmen, die diese Schnittstelle (entweder in dem Methodenaufruf implementiert oder als Parameter im Konstruktor) und seine dann Delete() Methode aufrufen, um den Lösch zu tun:

void MyMethod(string file) 
{ 
    // do whatever... 
    deleter.Delete(file); 
} 

um dies zu testen, habe ich ein Modell der IFileDeleter Schnittstelle machen können und einfach überprüfen, ob seine Delete() Methode aufgerufen worden war. Dies beseitigt die Notwendigkeit, ein echtes Dateisystem als Teil des Tests zu haben.

Das sieht vielleicht so aus, als wäre der Code komplexer (was es ist), aber es macht sich bezahlt, weil es viel einfacher zu testen ist.

+0

+1! Typemock kann statische Methoden vortäuschen, aber es ist besser, sie zu vermeiden (wenn sie verspottet werden müssen). – TrueWill

+0

+1 Vielen Dank für eine umfassende Antwort. Ich werde nur auf ein paar weitere Antworten warten (falls vorhanden), bevor ich eine Antwort aus Gründen des Wissensaustauschs auswähle – MSI

+0

Hm, was ich gefragt habe, war in der Tat ein bisschen albern, jetzt da ich deine Antwort gelesen habe. Ja, du hast Recht Ich habe den Punkt irgendwie verpasst, als ich die Frage gestellt habe. Es spottet, wenn echte Probleme auftauchen; nicht die Methode selbst testen, besonders wenn es nur eine Hilfsmethode ist. – MSI

7

Im Allgemeinen, wenn das Verfahren:

  • langsam
  • Ist lange
  • komplexe Logik
  • Verwendet das Dateisystem
  • zu einer Datenbank
  • Verbindet Enthält Ruft ein Web Service

Dann vermeiden Sie es statisch zu machen. (Siehe die Antwort von @adrianbanks für eine hervorragende Diskussion der Gründe und der Alternativen.)

Grundsätzlich nur statisch machen, wenn es sich um eine kurze In-Memory-Komfortmethode handelt (wie viele Erweiterungsmethoden).

+0

Ich mag deine Antwort sehr. Es macht Sinn, dass Sie die Logik des Statischen als Teil des SUT testen, um die Bequemlichkeit, die das Statische Dienstprogramm Ihnen bringt, wenn und nur wenn es keine der Merkmale, die Sie ausgeschrieben haben, hat. Bei einer schnellen, einfachen, nebenwirkungsfreien, statischen Methode gehen Sie davon aus, dass es sich um ein Primitiv handelt, eine Erweiterung Ihrer Sprache, und verwenden Sie es einfach in Ihren Einheiten ohne Isolation. –

8

Vermeiden von Statik ist sicherlich der Weg zu gehen, aber wenn Sie nicht können oder Sie mit Legacy-Code arbeiten, ist die folgende Option verfügbar. Im Anschluss an adrianbanks oben beantworten, lassen Sie uns sagen, dass Sie die folgenden Code haben (Entschuldigung, seine in Java da ich nicht weiß, C#):

public void someMethod() { 
    //do somethings 
    File.delete(); 
    //do some more things 
} 

Sie die File.delete Refactoring kann() in seine eigene Methode, wie dies:

public void someMethod() { 
    //do somethings 
    deleteFile(); 
    //do some more things 
} 

//protected allows you to override in a subclass 
protected void deleteFile() { 
    File.delete(); 
} 

und dann in der Vorbereitung für Ihren Unit-Test eine Mock-Klasse erstellen, die die ursprünglichen und Stubs aus dieser Funktionalität erweitert:

//Keep all the original functionality, but stub out the file delete functionality to 
//prevent it from using the real thing and while you're at it, keep a record that the 
//method was called. 
public class MockClass extends TheRealClass { 
    boolean fileDeleteCalled = false; 

    @Override 
    protected void deleteFile() 
     //don't actually delete the file, 
     //just record that the method to do so was called 
     fileDeleteCalled = true; 
    } 

    public boolean fileDeleteCalled() { 
     return fileDeleteCalled; 
    } 
} 

und schließlich in Ihrem Gerät zu testen:

//This would normally be instantiated in the @Before method 
private MockClass unitUnderTest = new MockClass(); 

@Test 
public void testFileGetsDeleted(){ 
    assertFalse(unitUnderTest.fileDeleteCalled()); 
    unitUnderTest.someMethod(); 
    assertTrue(unitUnderTest.fileDeleteCalled()); 
} 

Jetzt haben Sie alle Funktionen von irgendeinemethode() ausgeführt, ohne die Datei tatsächlich zu löschen, und Sie haben immer noch die Möglichkeit, wenn diese Methode aufgerufen wurde, um zu sehen.

+0

+1 für die großartige Idee. Danke Kumpel – MSI

+0

jemand geben ihm mehr Upvotes bitte für das nette Beispiel und Klärung – MSI