Frage

Ich bin sicher, die meisten von Ihnen viele automatisierte Tests schreiben, und dass Sie auch in einige typische Fehler beim Unit-Tests laufen.

Meine Frage ist folgen Sie Verhaltensregeln für das Schreiben von Tests, um Probleme in der Zukunft zu vermeiden? Um genauer zu sein: Was sind die Eigenschaften guter Unit-Tests oder wie schreiben Sie Ihre Tests

?

Sprache Agnostiker Vorschläge gefördert werden.

War es hilfreich?

Lösung

Lassen Sie mich durch Aufstecken Quellen beginnen - Pragmatische Einheit Tests in Java mit JUnit (Es gibt eine Version mit C # -Nunit auch .. aber ich habe diese eine .. seine Agnostiker zum größten Teil. Empfohlen.)

Gute Tests sein sollten A TRIP (Der acronymn nicht klebrig genug - ich habe einen Ausdruck der Spickzettel in dem Buch, dass ich mir dieses Recht hätte, um sicherzustellen, musste herausziehen .. )

  • Automatische : Hervorrufen von Tests sowie die Überprüfung Ergebnisse für PASS / FAIL sollte automatisch sein
  • Gründliche : Coverage; Obwohl Bugs um bestimmte Regionen in den Code clustern neigen, stellen Sie sicher, dass Sie alle wichtigen Wege und Szenarien testen .. Verwenden Sie Tools, wenn Sie müssen nicht getesteten Regionen kennen
  • wiederholbar : Die Tests sollten die gleichen Ergebnisse jedes Mal produzieren .. jedes Mal. Die Tests sollten nicht auf unkontrollierbare params verlassen.
  • Unabhängige : Sehr wichtig.
    • Tests sollte Test nur eine Sache, zu einem Zeitpunkt. Mehrere Behauptungen sind in Ordnung, solange sie alle die Prüfung ein Merkmal / Verhalten. Wenn ein Test fehlschlägt, sollte die Position des Problems ermitteln.
    • Tests sollten nicht aufeinander verlassen - isoliert. Keine Annahmen über Reihenfolge der Testausführung. Stellen Sie sicher, 'clean slate' vor jedem Test unter Verwendung von Setup / Teardown entsprechend
  • Professional : Auf langer Sicht werden Sie so vielen Testcode als Produktion (wenn nicht mehr), also den gleichen Standard des guten Designs für Ihren Test-Code folgen. Nun faktorisierter Methoden-Klassen mit Absicht offenbarenden Namen, keine Duplizierung, Tests mit guten Namen, etc.

  • Gute Tests laufen auch Schnell . jeder Test, der .. laufen über eine halbe Sekunde dauert muss auf gearbeitet werden. Je länger die Testsuite für einen Lauf nimmt .. desto seltener wird es ausgeführt werden. Je mehr Änderungen die Entwickler versuchen, zwischen den Läufen zu schleichen .. wenn etwas kaputt .. es wird länger dauern, um herauszufinden, welche Veränderung der Schuldige war.

Update 2010-08:

  • Lesbare : Dies kann einen Teil des Berufs in Betracht gezogen werden - aber es ist nicht genug betont werden kann. Ein Säuretest, jemanden zu finden wäre, der nicht Teil Ihres Teams ist und bittet ihn / sie das Verhalten im Test innerhalb von ein paar Minuten, um herauszufinden. Tests müssen wie Produktionscode gehalten werden - so machen es einfach, auch zu lesen, wenn es mehr Mühe. Tests symmetrisch sein sollte und prägnant (Test ein Verhalten zu einer Zeit) (ein Muster folgen). Verwenden Sie eine einheitliche Namenskonvention (zum Beispiel des TestDox Stil). Vermeiden Sie Poltern den Test mit „zufälligen Details“ .. werden ein minimalistisch.

Abgesehen von diesen, die meisten anderen sind Richtlinien, die auf Low-Nutzen-Arbeit abgeholzt: z.B. ‚Sie testen nicht Code, den Sie nicht besitzen‘ (zum Beispiel Drittanbieter-DLLs). Gehen Sie nicht über das Testen Getter und Setter. Halten Sie ein Auge auf die Kosten-Nutzen-Verhältnis oder Defektwahrscheinlichkeit.

Andere Tipps

  1. Schreiben Sie nicht ginormous Tests. Wie die 'Einheit' in 'Unit-Test' schlägt vor, von denen jeder als machen Atom und getrennt wie möglich. Wenn Sie müssen, schaffen Voraussetzungen Mock-Objekte, anstatt manuell zu viel von der typischen Benutzerumgebung neu zu erstellen.
  2. Dinge nicht testen, die offensichtlich arbeiten. Vermeiden Sie die Klassen Testen von einem Drittanbieter, vor allem die eine des Kern APIs des Rahmens liefern Sie Code in. Zum Beispiel, nicht testen um ein Element des Verkäufers Hashtable-Klasse hinzufügen.
  3. Betrachten Sie ein Code-Coverage-Tool wie NCover mit entdecken Fällen Rand, um Sie noch zu testen.
  4. Versuchen Sie, den Test zu schreiben vor die Umsetzung. Denken Sie an den Test eher als eine Spezifikation, die Ihre Implementierung haftet. Vgl auch verhaltensgetriebene Entwicklung, ein spezifischere Zweig der testgetriebenen Entwicklung.
  5. Seien Sie konsequent. Wenn Sie nur für einen Teil des Codes Tests schreiben, ist es kaum sinnvoll. Wenn Sie in einem Team arbeiten, und einige oder alle anderen nicht-Tests schreiben, es ist nicht sehr nützlich, auch nicht. Überzeugen Sie sich selbst und alle anderen von der Wichtigkeit (und zeitsparende Eigenschaften) von Tests oder nicht stören.

Die meisten der hier Antworten scheinen Unit-Tests Best Practices im Allgemeinen zu adressieren (wann, wo, warum und was), anstatt tatsächlich die das Schreiben von Tests selbst (wie). Da die Frage Teil schien ziemlich spezifisch auf dem „Wie“, dachte ich, ich diesen Beitrag würde, von einer „braunen Tasche“ Präsentation genommen, die ich in meiner Firma durchgeführt.

Womp von 5 Laws of Writing Tests:


1. Verwenden Sie lange, beschreibende Testmethodennamen.

   - Map_DefaultConstructorShouldCreateEmptyGisMap()
   - ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()
   - Dog_Object_Should_Eat_Homework_Object_When_Hungry()

2. Schreiben Sie Ihre Tests in einem Anordnen / Act / Assert Stil .

  • Während diese Unternehmensstrategie um für eine Weile gewesen und rief viele Dinge, die Einführung vor kurzem der „AAA“ Akronym hat war eine gute Möglichkeit, dies zu vermitteln. Macht alle Tests im Einklang mit AAA-Stil macht sie leicht zu lesen und halten.

3. Geben Sie immer eine Fehlermeldung mit dem Asserts.

Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element 
processing events was raised by the XElementSerializer");
  • Eine einfache, aber lohnende Praxis, die es offensichtlich in Ihrem Läufer Anwendung macht, was ausgefallen ist. Wenn Sie nicht eine Nachricht liefern, werden Sie in der Regel etwas wie „Erwartete wahr, falsch war“ erhalten Ausgabe in Ihrem Versagen, die Sie tatsächlich gehen lesen Sie den Test macht, um herauszufinden, was falsch ist.

4. Kommentieren Sie den Grund für den Test - was ist das Geschäft Annahme

  /// A layer cannot be constructed with a null gisLayer, as every function 
  /// in the Layer class assumes that a valid gisLayer is present.
  [Test]
  public void ShouldNotAllowConstructionWithANullGisLayer()
  {
  }
  • Das mag selbstverständlich erscheinen, aber diese Praxis schützt die Integrität Ihre Tests von Leuten, die dies nicht tun verstehen, den Grund für den Test an erster Stelle. Ich habe viele gesehen Tests erhalten entfernt oder modifiziert wird, dass waren völlig in Ordnung, nur weil die Person nicht verstehen, die Annahmen, dass der Test war zu überprüfen.
  • Wenn der Test ist trivial oder das Verfahren Name ist ausreichend beschreibend, es kann zulässig sein, die verlassen Kommentar aus.

5. Jeder Test muss der Zustand der Ressource immer zurückkommen es berührt

  • Verwenden Sie spottet, wo möglich, zu vermeiden, Umgang mit realen Ressourcen.
  • Cleanup muss bei der Prüfung erfolgen Niveau. Tests müssen nicht irgendwelche Vertrauen auf die Reihenfolge der Ausführung.

Halten Sie diese Ziele im Auge (angepasst aus dem Buch xUnit Testmuster von Meszaros)

  • Die Tests sollten Risiko verringern, nicht einführen.
  • sollten Tests einfach zu laufen.
  • sollten Tests leicht zu halten, wie das System entwickelt um sie herum

Einige Dinge machen dies einfacher:

  • Die Tests sollten nur scheitern, weil die ein Grund.
  • Die Tests sollten nur eine Sache testen
  • Minimieren Test Abhängigkeiten (kein Abhängigkeiten von Datenbanken, Dateien, ui etc.)

Vergessen Sie nicht, dass Sie zu intergration Tests mit Ihrem xUnit Rahmen tun können aber halten intergration Tests und Unit-Tests trennen

Die Tests sollten isoliert werden. Ein Test sollte nicht auf andere angewiesen. Noch weiter sollte ein Test nicht auf externe Systeme angewiesen. Mit anderen Worten, Test Ihre Code, nicht der Code der Code hängt on.You diese Wechselwirkungen als Teil Ihrer Integration oder Funktionstests testen können.

Einige Eigenschaften von großen Unit-Tests:

  • Wenn ein Test fehlschlägt, sollte es sofort klar, wo das Problem liegt. Wenn Sie den Debugger verwenden müssen, das Problem auf die Spur, dann sind Ihre Tests nicht genug körnig. genau eine Aussage pro Test haben, hilft hier.

  • Wenn Sie Refactoring, sollten keine Tests fehlschlagen.

  • Die Tests sollten so schnell laufen, dass Sie nie laufen zögern.

  • sollten alle Tests bestanden immer; kein nicht-deterministische Ergebnisse.

  • Unit-Tests gut berücksichtigt werden sollen, genau wie Ihr Produktionscode.

@Alotor: Wenn Sie darauf hindeutet, dass eine Bibliothek nur Unit-Tests an seiner externen API haben sollte, ich nicht zustimmen. Ich möchte Unit-Tests für jede Klasse, einschließlich der Klassen, die ich an externe Anrufer nicht aussetzen. (Allerdings wenn ich das Bedürfnis verspüren, Tests zu schreiben für private Methoden, dann muss ich Refactoring. )


EDIT: Es gab einen Kommentar über Duplikation verursacht durch „eine Behauptung pro Test“. Insbesondere wenn Sie einen Code haben ein Szenario einzurichten, und dann mehrere Behauptungen darüber machen wollen, aber nur eine Behauptung pro Test haben, können Sie das Setup über mehrere Tests Duplikation.

Ich nehme nicht diesen Ansatz. Stattdessen verwende ich Prüfvorrichtungen pro Szenario . Hier ist ein einfaches Beispiel:

[TestFixture]
public class StackTests
{
    [TestFixture]
    public class EmptyTests
    {
        Stack<int> _stack;

        [TestSetup]
        public void TestSetup()
        {
            _stack = new Stack<int>();
        }

        [TestMethod]
        [ExpectedException (typeof(Exception))]
        public void PopFails()
        {
            _stack.Pop();
        }

        [TestMethod]
        public void IsEmpty()
        {
            Assert(_stack.IsEmpty());
        }
    }

    [TestFixture]
    public class PushedOneTests
    {
        Stack<int> _stack;

        [TestSetup]
        public void TestSetup()
        {
            _stack = new Stack<int>();
            _stack.Push(7);
        }

        // Tests for one item on the stack...
    }
}

Was Sie nach Abgrenzung der Verhaltensweisen der Klasse unter Test.

  1. Überprüfung der erwarteten Verhaltensweisen.
  2. Überprüfung von Fehlerfällen.
  3. Abdeckung aller Codepfade innerhalb der Klasse.
  4. Trainieren alle Member-Funktionen innerhalb der Klasse.

Die grundlegende Absicht ist Ihr Vertrauen in dem Verhalten der Klasse erhöhen.

Dies ist besonders nützlich, wenn sie bei Refactoring Code suchen. Martin Fowler hat eine interessante Artikel Bezug auf seiner Website Testen über.

HTH.

prost,

Rob

Test sollte ursprünglich scheitern. Dann sollten Sie den Code schreiben, die sie passieren macht, sonst laufen Sie Gefahr des Schreibens einen Test durchführen, die abgehört und immer passiert.

Ich mag die richtige BICEP Akronym aus der oben genannten

Gute Tests müssen wartbar sein.

Ich habe nicht ganz herausgefunden, wie dies für komplexe Umgebungen zu tun.

Alle Lehrbücher beginnen zu kommen unglued als Code-Basis beginnt erreicht in die Hunderte von 1000 oder Millionen von Zeilen Code.

  • Team Interaktionen explodieren
  • Anzahl der Testfälle explodieren
  • Interaktionen zwischen den Komponenten explodiert.
  • Zeit, um alle Unittests bauen wird ein wesentlicher Teil der Build-Zeit
  • eine API-Änderung, um Hunderte von Testfällen kräuseln kann. Auch wenn die Produktion Codeänderung war einfach.
  • die Anzahl der Ereignisse erforderlichen Prozesse in den richtigen Zustand nimmt sequenzieren, die wiederum Testausführungszeit erhöht.

Gute Architektur kann einige der Interaktion Explosion kontrollieren, aber zwangsläufig als Systeme werden immer komplexer das automatisierte Testsystem mit ihm wächst.

Dies ist, wo Sie mit beginnen mit Kompromissen zu tun:

  • nur testen externen API sonst Refactoring Einbauten führt zu einem signifikanten Testfall Nacharbeit.
  • Auf- und Abbau der einzelnen Tests wird komplizierter als ein gekapseltes Subsystem mehr Zustand beibehält.
  • nächtliche Zusammenstellung und automatisierte Testdurchführung wachsen Stunden.
  • erhöhte Kompilierung und Ausführungszeiten bedeutet, dass Designer nicht oder werden nicht alle Tests ausführen
  • reduzieren Testausführungszeiten berücksichtigen Sie Sequenzierungstests reduzieren zu nehmen einzurichten und Abrüsten

Sie müssen auch entscheiden:

wo speichern Sie Testfälle in Ihrer Code-Basis?

  • Wie dokumentieren Sie Ihre Testfälle?
  • können Prüfadapter wiederverwendet werden Testfall Wartung sparen?
  • was passiert, wenn eine nächtliche Testfallausführung fehlschlägt? Wer macht die Triage?
  • Wie pflegen Sie die Mock-Objekte? Wenn Sie 20 Module all ihren eigenen Geschmack eines Mock Logging-API verwenden, das Ändern der API Wellen schnell. Nicht nur, dass die Testfälle ändern, aber die 20 Mock-Objekte ändern. Diese 20 Module wurden über mehrere Jahre geschrieben von vielen verschiedenen Teams. Es ist eine klassische Weiterverwendung Problem.
  • Einzelpersonen und verstehen ihre Teams den Wert von automatisierten Tests, die sie nicht nur gerne, wie das andere Team es tut. : -)

ich könnte weitermachen für immer, aber mein Punkt ist, dass:

Tests müssen wartbar sein.

Ich bedeckte diese Grundsätze vor einiger Zeit in Diese MSDN Magazine Artikel was ich denke, ist wichtig für jeden Entwickler zu lesen.

So wie ich „gut“ Unit-Tests zu definieren, ist, wenn sie die folgenden drei Eigenschaften besitzen:

  • Sie sind lesbar (Namensgebung, behauptet, Variablen, Länge, Komplexität ..)
  • Sie sind wartbaren (keine Logik, nicht über angegeben, zustandsbasierte, Refactoring ..)
  • Sie sind vertrauenswürdig (testen Sie das Richtige, isoliert, nicht Integrationstests ..)
  • Unit Testing testet nur die externe API Ihrer Einheit, sollten Sie nicht internes Verhalten testen.
  • Jeder Test eines Testcase sollte testen, eine (und nur eine) Methode innerhalb dieser API.
    • Aditional Testfälle sollten für Fehlerfälle aufgenommen werden.
  • Testen Sie die Reichweite Ihrer Tests. Sobald ein Gerät getestet hat, soll das 100% der Leitungen in diesem Gerät ausgeführt worden

Jay Felder hat eine viele gute Ratschläge über Unit-Tests zu schreiben und gibt es eine Post, wo er die wichtigsten Ratschläge zusammenfassen . Dort werden Sie lesen, dass Sie kritisch über Ihren Kontext und Richter denken sollte, wenn der Rat an Sie wert ist. Sie erhalten eine Tonne erstaunliche Antworten hier, aber es ist bis zu entscheiden, welche für Ihren Kontext am besten ist. Versuchen Sie, und nur Refactoring, wenn es riecht schlecht für Sie.

Mit freundlichen Grüßen

Sie niemals davon aus, dass eine triviale 2 line Methode funktioniert. Schreibt einen schnellen Unit-Test ist der einzige Weg, um den fehlenden Nulltest, fehl am Platze Minuszeichen und / oder subtile Scoping Fehler zu verhindern, dass Sie beißt, unweigerlich, wenn man noch weniger Zeit damit zu beschäftigen als jetzt.

Ich zweite "A TRIP" Antwort, mit der Ausnahme, dass Tests aufeinander verlassen sollte !!!

Warum?

DRY - Do not Repeat Yourself - gilt für Tests, wie gut! Test Abhängigkeiten können zu 1) helfen Rüstzeit, 2) speichert Befestigung Ressourcen und 3) zu ermitteln, um Ausfälle zu speichern. Natürlich nur vorausgesetzt, dass Ihr Test-Framework Abhängigkeiten First-Class unterstützt. Ansonsten gebe ich zu, sind sie schlecht.

Follow-up http://www.iam.unibe.ch/~ SCG / Forschung / JExample /

Oft Unit-Tests werden auf Mock-Objekt oder Mock-Daten. Ich mag drei Arten von Unit-Tests schreiben:

  • „transient“ Unit-Tests: Sie schaffen ihre eigenen Mock-Objekte / Daten und testen ihre Funktion mit ihm, aber alles zerstören und keine Spur hinterlassen (wie keine Daten in einer Testdatenbank)
  • „persistent“ Unit-Test: Sie testen Funktionen im Code Objekte / Daten erstellen, die später durch erweiterte Funktion benötigt werden, für ihren eigenen Unit-Test (Vermeidung von für jene erweiterte Funktion jedes Mal ihre eigene Reihe von Mock-Objekten erstellen / data)
  • "persistent-basierte" Unit-Tests. Unit-Tests unter Verwendung von Mock-Objekten / Daten, die bereits vorhanden sind (weil in einer anderen Einheit Testsitzung erstellt) durch die persistent Unit-Tests

Der Punkt ist, zu vermeiden, zu wiederholen alles , um alle Funktionen testen zu können.

  • Ich laufe sehr oft die dritte Art, da alle Mock-Objekte / Daten sind schon da.
  • Ich betreibe die zweite Art, wenn meine Modellwechsel.
  • Ich betreiben den ersten die grundlegendsten Funktionen hin und wieder zu überprüfen, um grundlegende Regressionen zu überprüfen.

Denken Sie an die zwei Arten von Tests und behandeln sie anders -. Funktionstests und Performance-Tests

Verwenden Sie verschiedene Eingänge und Metriken für jeden. Sie müssen möglicherweise unterschiedliche Software für jede Art von Test verwenden.

Ich verwende eine konsistente Test Konvention beschrieben Benennung von Roy Osherove des Einheit Test Naming Standards Jede Methode in einem bestimmten Testfall-Klasse hat die folgende Namensgebung Stil MethodUnderTest_Scenario_ExpectedResult.

    Der erste Testname Abschnitt ist der Name des Verfahrens, bei dem getesteten System.
    Als nächstes ist das spezifische Szenario, das getestet wird.
    ist schließlich die Ergebnisse dieses Szenario.

Jeder Abschnitt verwendet Ober Camel Fall und wird durch eine unter Partitur begrenzt.

Ich habe dies nützlich gefunden, wenn ich den Test der Test durchgeführt durch den Namen der Methode im Test gruppiert sind. Und hat eine Konvention andere Entwickler erlaubt, den Test Absicht zu verstehen.

ich anhänge auch Parameter an den Methodennamen, wenn die Methode im Test überlastet wurde.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top