it-swarm.com.de

Unit Testing Methoden für ungültig erklären?

Was ist der beste Weg, um eine Methode, die nichts zurückgibt, einem Komponententest zu unterziehen? Speziell in c #.

Was ich wirklich versuche zu testen, ist eine Methode, die eine Protokolldatei auf bestimmte Zeichenfolgen analysiert. Die Zeichenfolgen werden dann in eine Datenbank eingefügt. Nichts, was vorher noch nicht gemacht wurde, aber für TDD SEHR neu ist. Ich frage mich, ob es möglich ist, dies zu testen, oder ob es etwas ist, das nicht wirklich getestet wird.

150
jdiaz

Wenn eine Methode nichts zurückgibt, ist dies eine der folgenden Methoden

  • imperativ - Sie fordern das Objekt entweder auf, sich selbst etwas anzutun. Zum Beispiel den Status zu ändern (ohne eine Bestätigung zu erwarten). Es wird davon ausgegangen, dass dies der Fall sein wird getan)
  • informativ - einfach jemanden benachrichtigen, dass etwas passiert ist (ohne eine Aktion oder Reaktion zu erwarten).

Imperative Methoden - Sie können überprüfen, ob die Aufgabe tatsächlich ausgeführt wurde. Überprüfen Sie, ob tatsächlich eine Statusänderung stattgefunden hat. z.B.

void DeductFromBalance( dAmount ) 

kann getestet werden, indem überprüft wird, ob der Saldo nach dieser Nachricht tatsächlich unter dem Anfangswert von dAmount liegt

Informationsmethoden - sind selten als Mitglied der öffentlichen Schnittstelle des Objekts ... daher normalerweise nicht Unit-getestet. Wenn Sie dies jedoch tun müssen, können Sie überprüfen, ob die Bearbeitung einer Benachrichtigung erfolgt. z.B.

void OnAccountDebit( dAmount )  // emails account holder with info

kann getestet werden, indem überprüft wird, ob die E-Mail gesendet wird

Veröffentlichen Sie mehr Details zu Ihrer eigentlichen Methode und die Leute werden besser antworten können.
Update : Ihre Methode macht 2 Dinge. Ich würde es tatsächlich in zwei Methoden aufteilen, die jetzt unabhängig getestet werden können.

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

String [] kann einfach überprüft werden, indem die erste Methode mit einer Dummy-Datei und erwarteten Strings versehen wird. Der zweite ist etwas knifflig. Sie können entweder einen Mock (Google oder Search Stackoverflow für Mocking-Frameworks) verwenden, um die DB nachzuahmen, oder die tatsächliche DB treffen und überprüfen, ob die Zeichenfolgen an der richtigen Stelle eingefügt wurden. Check this thread für ein paar gute Bücher ... Ich würde Pragmatic Unit Testing empfehlen, wenn Sie in einer Krise sind.
Im Code würde es gerne verwendet

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
139
Gishu

Testen Sie die Nebenwirkungen. Das beinhaltet:

  • Wirft es irgendwelche Ausnahmen? (Wenn dies der Fall sein sollte, überprüfen Sie, ob dies der Fall ist. Wenn dies nicht der Fall ist, versuchen Sie es mit einigen Eckfällen. Wenn Sie nicht vorsichtig sind, sind Nullargumente die naheliegendste Sache.)
  • Spielt es gut mit seinen Parametern? (Wenn sie veränderlich sind, mutiert es sie, wenn es nicht sollte und umgekehrt?)
  • Hat es die richtigen Auswirkungen auf den Status des Objekts/Typs, auf den Sie es aufrufen?

Natürlich gibt es eine Grenze, wie viel Sie testen können. Sie können zum Beispiel im Allgemeinen nicht mit jeder möglichen Eingabe testen. Pragmatisch testen - genug, um Ihnen die Gewissheit zu geben, dass Ihr Code richtig entworfen und implementiert wurde, und genug, um als ergänzende Dokumentation für das zu dienen, was ein Aufrufer erwarten könnte.

59
Jon Skeet

Wie immer: Testen Sie, was die Methode leisten soll!

Sollte es irgendwo den globalen Status ändern (uuh, Codegeruch!)?

Sollte es in eine Schnittstelle aufrufen?

Sollte es eine Ausnahme auslösen, wenn es mit den falschen Parametern aufgerufen wird?

Sollte es keine Ausnahme machen, wenn es mit den richtigen Parametern aufgerufen wird?

Sollte es ...?

28
David Schmitt

Ungültige Rückgabetypen/Unterprogramme sind alte Nachrichten. Ich habe in 8 Jahren keinen Void return type (es sei denn, ich war extrem faul) gemacht (Ab dem Zeitpunkt dieser Antwort, also nur ein bisschen bevor diese Frage gestellt wurde).

Anstelle einer Methode wie:

public void SendEmailToCustomer()

Erstellen Sie eine Methode, die dem int.TryParse () -Paradigma von Microsoft folgt:

public bool TrySendEmailToCustomer()

Möglicherweise gibt es keine Informationen, die Ihre Methode zur Verwendung auf lange Sicht zurückgeben muss, aber die Rückgabe des Zustands der Methode nach der Ausführung ihrer Aufgabe ist für den Aufrufer von großem Nutzen.

Außerdem ist bool nicht der einzige Zustandstyp. Es gibt eine Reihe von Fällen, in denen eine zuvor erstellte Subroutine tatsächlich drei oder mehr verschiedene Zustände (Gut, Normal, Schlecht usw.) zurückgeben kann. In diesen Fällen würden Sie nur verwenden

public StateEnum TrySendEmailToCustomer()

Während das Try-Paradigma diese Frage zum Testen einer Stornorückgabe ein wenig beantwortet, gibt es auch andere Überlegungen. Während/nach einem "TDD" -Zyklus würden Sie beispielsweise "Refactoring" durchführen und feststellen, dass Sie mit Ihrer Methode zwei Dinge tun ... und damit das "Prinzip der einzigen Verantwortung" brechen. Das sollte also zuerst erledigt werden. Zweitens haben Sie möglicherweise eine Abhängigkeit identifiziert ... Sie berühren "Persistente" Daten.

Wenn Sie die Datenzugriffsaufgaben in der fraglichen Methode ausführen, müssen Sie eine Umstrukturierung in eine n-Tier- oder n-Layer-Architektur vornehmen. Wir können jedoch davon ausgehen, dass Sie mit "Die Zeichenfolgen werden dann in eine Datenbank eingefügt" tatsächlich eine Geschäftslogikschicht oder etwas anderes aufrufen. Ja, das nehmen wir an.

Wenn Ihr Objekt instanziiert wird, wissen Sie jetzt, dass Ihr Objekt Abhängigkeiten aufweist. Hier müssen Sie entscheiden, ob Sie eine Abhängigkeitsinjektion für das Objekt oder für die Methode durchführen möchten. Das bedeutet, dass Ihr Konstruktor oder die betreffende Methode einen neuen Parameter benötigt:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

Jetzt, da Sie eine Schnittstelle Ihres Unternehmens-/Datenebenenobjekts akzeptieren können, können Sie diese während der Komponententests nachahmen und haben keine Abhängigkeiten oder Angst vor "versehentlichen" Integrationstests.

In Ihrem Live-Code übergeben Sie also ein REAL IBusinessDataEtc -Objekt. Bei Unit Testing übergeben Sie jedoch ein MOCK IBusinessDataEtc -Objekt. In diesem Mock können Sie Nicht-Interface-Eigenschaften wie int XMethodWasCalledCount oder etwas, dessen Status aktualisiert wird, wenn die Schnittstellenmethoden aufgerufen werden.

Ihr Unit-Test wird also Ihre (n) in Frage kommende (n) Methode (n) durchgehen, eine beliebige Logik ausführen und eine oder zwei Methoden oder eine ausgewählte Gruppe von Methoden in Ihrem IBusinessDataEtc -Objekt aufrufen. Wenn Sie Ihre Aussagen am Ende Ihres Unit-Tests machen, müssen Sie jetzt einige Dinge testen.

  1. Der Status der "Subroutine", die jetzt eine Try-Paradigm-Methode ist.
  2. Der Status Ihres Scheinobjekts IBusinessDataEtc.

Weitere Informationen zu Ideen für die Abhängigkeitsinjektion auf Konstruktionsebene ... in Bezug auf Komponententests ... finden Sie unter Builder-Entwurfsmuster. Es fügt eine weitere Schnittstelle und Klasse für jede aktuelle Schnittstelle/Klasse hinzu, die Sie haben, aber sie sind sehr klein und bieten RIESIGE Funktionserweiterungen für ein besseres Unit-Testing.

10
Suamere

es wird Auswirkungen auf ein Objekt haben. Fragen Sie nach dem Ergebnis des Effekts. Wenn es keine sichtbaren Auswirkungen hat, lohnt es sich nicht, das Gerät zu testen!

5
Keith Nicholas

Vermutlich macht die Methode etwas und kehrt nicht einfach zurück?

Angenommen, dies ist der Fall, dann:

  1. Wenn der Status des Besitzerobjekts geändert wird, sollten Sie testen, ob sich der Status ordnungsgemäß geändert hat.
  2. Wenn es ein Objekt als Parameter akzeptiert und dieses Objekt ändert, sollten Sie testen, ob das Objekt korrekt geändert wurde.
  3. Wenn in bestimmten Fällen Ausnahmen ausgelöst werden, prüfen Sie, ob diese Ausnahmen korrekt ausgelöst wurden.
  4. Wenn sich sein Verhalten aufgrund des Zustands seines eigenen Objekts oder eines anderen Objekts ändert, stellen Sie den Zustand ein, und testen Sie die Methode mit einer der drei oben genannten Testmethoden.

Wenn Sie uns wissen lassen, was die Methode tut, könnte ich genauer sein.

4
David Arno

Versuche dies:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}
4
Nathan Alard

Verwenden Sie Rhino Mocks , um festzulegen, welche Aufrufe, Aktionen und Ausnahmen zu erwarten sind. Vorausgesetzt, Sie können Teile Ihrer Methode verspotten oder herausfiltern. Schwer zu wissen, ohne hier einige Einzelheiten über die Methode oder sogar den Kontext zu kennen.

3
dove

Kommt darauf an, was es tut. Wenn es Parameter hat, übergeben Sie Mocks, die Sie später fragen können, ob sie mit dem richtigen Parametersatz aufgerufen wurden.

2
André

Sie können es sogar so versuchen:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}
2
Reyan Chougle

Welche Instanz Sie auch immer verwenden, um die void-Methode aufzurufen. Sie können einfach Verfiy verwenden.

Beispielsweise:

In meinem Fall ist es _Log ist die Instanz und LogMessage ist die zu testende Methode:

try
{
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch 
{
    Assert.IsFalse(ex is Moq.MockException);
}

Wird mit Verify eine Ausnahme ausgelöst, weil die Methode, bei der der Test fehlschlagen würde, fehlgeschlagen ist?

0