2008-08-11 8 views
1

Was ist der beste Weg, um eine Funktion zu testen, die einen Fehler verursacht? Oder testen Sie eine Funktion, die weitgehend immun gegen Fehler ist?Testen einer Funktion, bei der ein Fehler auftritt

Zum Beispiel; Ich habe eine I/O Completion Port-Klasse, die den Konstruktor auslöst, wenn der Port nicht korrekt initialisiert werden kann. Dies verwendet die Win32-Funktion von CreateIoCompletionPort in der Initialisiererliste. Wenn das Handle nicht richtig eingestellt ist - ein Wert ungleich null -, wird der Konstruktor eine Ausnahme auslösen. Ich habe nie gesehen, dass diese Funktion fehlschlägt.

Ich bin mir ziemlich sicher, dass diese (und andere Funktionen, wie es in meinem Code), wenn sie korrekt verhalten ausfallen, wird der Code 50 Zeilen lang ist weiß-Raum einschließlich, so meine Fragen

a) sind, ist es es lohnt sich zu testen, dass es
b werfen wird und wenn es sich lohnt zu testen, wie?
c) sollten einfache Wrapper-Klassen, wie diese Unit-getestet werden?

Für b) dachte ich über überschreiben CreateIoCompletionPort und übergibt die Werte durch. Im Unit-Test überschreiben Sie ihn und veranlassen ihn, 0 zurückzugeben, wenn ein bestimmter Wert übergeben wird. Da dies jedoch im Konstruktor verwendet wird, muss dieser statisch sein. Scheint dies gültig oder nicht?

Antwort

2

Es lohnt sich auf jeden Fall, Fehlerbedingungen zu testen, und zwar sowohl, dass Ihre Klasse ordnungsgemäß eine Ausnahme auslöst, wenn Sie es wünschen, als auch, dass Ausnahmen in der Klasse ordnungsgemäß behandelt werden.

Dies kann einfach getan werden, wenn Sie auf ein Objekt handeln, das an den Konstruktor übergeben wird ... übergeben Sie einfach einen Schein. Wenn nicht, tendiere ich dazu, die Funktionalität lieber in eine geschützte Methode zu verschieben und die geschützte Methode zu überschreiben, um meinen Fehlerfall hervorzurufen. Ich werde Java als Beispiel verwenden, aber es sollte die Ideen zu einem C# Fall Port leicht genug sein:

public class MyClass { 
    public MyClass() throws MyClassException { 
     // Whatever, including a call to invokeCreateIoCompletionPort 
    } 

    protected int invokeCreateIoCompletionPort(String str, int i) { 
     return StaticClass.createIoCompletionPort(str, i); 
    } 
} 

public class MyTest { 
    public void myTest() { 
     try { 
      new MyClass(); 
      fail("MyClassException was not thrown!"); 
     } catch (MyClassException e) { 
     } 
    } 

    private static class MyClassWrapper extends MyClass { 
     @Override 
     protected int invokeCreateIoCompletionPort(String str, int i) { 
      throw new ExpectedException(); 
     } 
    } 
} 

Wie Sie sehen können, ist es recht einfach zu testen, ob eine Ausnahme von dem Konstruktor geworfen wird oder Methode, die Sie testen, und es ist auch ziemlich einfach, eine Ausnahme von einer externen Klasse zu injizieren, die eine Ausnahme auslösen kann. Entschuldigung, ich benutze nicht Ihre tatsächliche Methode, ich habe nur den Namen verwendet, um zu veranschaulichen, wie es klang, als ob Sie es benutzen, und wie ich die Fälle testen würde, die es klang, die Sie testen wollten.

Grundsätzlich können alle von Ihnen bereitgestellten API-Details in der Regel getestet werden. Wenn Sie wissen möchten, dass Sonderfälle so funktionieren, wie sie sollten, sollten Sie sie wahrscheinlich testen.

1

Sie sollten in Erwägung ziehen, Ihren Code so zu schreiben, dass Sie sich über Ihren I/O-Completion-Port lustig machen können. Stellen Sie eine Schnittstelle/abstrakte Klasse her, die die Methoden verfügbar macht, die Sie für das E/A-Objekt benötigen, und schreiben und testen Sie die Implementierung, die Dinge tut, wie sie soll (und eine Option, um vielleicht einen Fehler zu simulieren).

AFAIK Es ist eine gängige Praxis, externe Ressourcen zu testen, wenn Komponententests durchgeführt werden, um Abhängigkeiten zu minimieren.

3

Wenn Sie dies in .NET tun, ist es ein ExpectedException Attribut, das Sie Ihren Test hinzufügen:

[Test, ExpectedException(typeof(SpecificException), "Exception's specific message")] 
public void TestWhichHasException() 
{ 
    CallMethodThatThrowsSpecificException(); 
} 

-Test wird passieren, wenn die Ausnahme von dieser Art und mit der angegebenen Meldung ausgelöst. Das Attribut hat andere Überladungen einschließlich InnerExceptions usw.

0

Sound wie C++ zu mir. Sie benötigen eine Naht, um die Win32-Funktionen zu verspotten. Z.B.In Ihrer Klasse würden Sie eine geschützte Methode CreateIoCompletionPort() erstellen, die ::CreateIoCompletionPort() aufruft, und für Ihren Test erstellen Sie eine Klasse, die von Ihrer I/O Completion Port-Klasse abgeleitet ist und CreateIoCompletionPort() überschreibt, um nur NULL zurückzugeben. Ihre Produktionsklasse verhält sich immer noch wie geplant, aber Sie können jetzt einen Fehler in der CreateIoCompletionPort()-Funktion simulieren.

Diese Technik stammt aus Michael Feathers Buch "Effektiv mit Legacy-Code arbeiten".