Codierungsstandards für Komponententests

22

Wenn wir über Codierungsstandards sprechen, beziehen wir uns normalerweise auf den Code des Programms selbst, aber was ist mit den Komponententests? Gibt es bestimmte Kodierungsrichtlinien, die nur für Komponententests gelten? Was sind Sie?

EpsilonVector
quelle

Antworten:

12

Ich kann mir drei Unterschiede im Codierungsstil für Testcode vorstellen.

Bei der Benennung von Testmethoden folge ich dem Muster von shouldDoSomethingWhenSomeConditionHolds.

Innerhalb des Tests ist es üblich, das folgende Abstandsmuster einzuhalten:

@Test
shouldReturnAccountBalenceWhenGetBalenceIsCalled() {
    // Some lines 
    // of setup code
    // go here.

    // The action being tested happens after a blank line.

    // An assertion follows another blank line.
}

Einige bestehen auf nur einer Aussage pro Test, aber das ist alles andere als allgemein.

DRY (Don't Repeat Yourself) spielt im Testcode eine geringere Rolle als im Produktionscode. Während wiederholter Code in eine setUp-Methode oder eine testUtils-Klasse eingefügt werden sollte, führt das Streben nach einer Null-Wiederholung im Testcode zu eng gekoppelten und unflexiblen Tests, was ein Refactoring verhindert.

Eric Wilson
quelle
Natürlich gibt es eine Vielzahl von Mustern, weshalb Sie auch eine Antwort geben sollten.
Eric Wilson
10
Das ist das Arrangier-, Act-, Assert- Muster.
StuperUser
TROCKEN ist immer noch wichtig. Wenn Sie dieselben Asserts in mehreren Tests ausführen müssen, erstellen Sie eine gemeinsame Funktion und rufen Sie sie in allen Tests auf.
MiFreidgeim SO-aufhören, böse zu sein
@MichaelFreidgeim Vielleicht reden wir nur über Abschlüsse, aber ich habe eine deutlich höhere Toleranz für Wiederholungen im Testcode. Ich habe mehrere Erfahrungen mit der Erstellung von Testsuiten mit sehr geringen Wiederholungen gemacht und festgestellt, dass die Tests schwer zu ändern und zu verstehen waren, wenn sich die Anforderungen änderten. Dann habe ich aufgehört, mich in Tests um DRY zu kümmern, und meine Testsuiten waren benutzerfreundlicher. <Achselzucken>
Eric Wilson
16

Roy Osherove empfiehlt das folgende Muster für die Benennung Ihrer Tests:

NameOfMethodUnderTest_StateUnderTest_ExpectedBehavior() 

Siehe http://weblogs.asp.net/rosherove/archive/2005/04/03/TestNamingStandards.aspx

Robert Harvey
quelle
Ich stimme Roy zu. Es verbessert die Lesbarkeit, obwohl ReSharper mir immer wieder sagt, dass ich sie entfernen soll NameOfMethodUnderTestStateUnderTestExpectedBehavior();)
Oscar Mederos
Wie funktioniert das, wenn die Methode überladen ist, sodass es mehrere Methoden mit demselben Namen geben kann?
Narendra Pathai
6

Die Hauptsache ist, sich daran zu erinnern, dass Unit-Tests im Wesentlichen Mini-Spezifikationen sind. Das bedeutet, dass der Schwerpunkt immer auf der Lesbarkeit liegen muss.

Erstens bedeutet dies, dass Namen klar kommunizieren müssen, was geprüft wird und was behauptet wird.

Zweitens, was manchmal vergessen wird, ist, dass sie als Spezifikationen genau das tun sollten - das Verhalten spezifizieren. Unit-Tests sollten also keine Logik enthalten - oder sie könnten in die Falle geraten, die Funktionalität des Programms zu wiederholen, anstatt sie zu testen.

Manchmal umfassen die Tests Objekte, deren Einrichtung komplex ist. Sie sollten sich bemühen, diese Einrichtungslogik von Ihren Tests zu trennen, indem Sie beispielsweise eine Objektmutter oder einen Testdatengenerator verwenden .

Ich werde nur mit ein paar Buchempfehlungen abrunden:

xUnit-Testmuster: Refactoring-Testcode: Ausgezeichnetes Buch, manche sagen, es ist ein bisschen trocken, aber ich denke nicht. Erläutert ausführlich die verschiedenen Möglichkeiten, Tests zu organisieren und sie wartbar zu halten. Relevant, wenn Sie etwas wie NUnit usw. verwenden.

Die Kunst des Unit-Testens: Mit Beispielen in .Net : Das beste Buch über die Grundlagen des Schreibens und Wartens von Tests. Obwohl ich wirklich neu bin, finde ich die Verspottungsabschnitte schon ein wenig altmodisch, da die AAA-Syntax mittlerweile eher Standard als nur eine andere Methode ist.

Wachsende objektorientierte Software, angeleitet von Tests : Dieses Buch ist einfach unglaublich! Mit Abstand das beste und das einzige Buch für Komponententests, das Komponententests als Bürger erster Klasse in den Entwurfsprozess einbezieht. Ich habe dies gelesen, als es eine öffentliche Beta war, und empfehle es seitdem. Ausgezeichnetes, realistisch gearbeitetes Beispiel, das im gesamten Buch verwendet wird. Ich würde empfehlen, zuerst Roys Buch zu lesen.

FinnNk
quelle
IMHO ist es in Ordnung, dass Komponententests Logik enthalten: Es ist absolut vernünftig, eine hochoptimierte, effiziente Version eines Algorithmus zu testen, indem ein naiver Algorithmus verwendet wird, der dasselbe tut, um das richtige Verhalten zu bestimmen. Stellen Sie sich zum Beispiel vor, Sie testen eine Hash-Tabelle, indem Sie ein lineares, suchbasiertes assoziatives Array erstellen.
DSIMCHA
2
Ja, aber das gehört außerhalb des Tests in den Testdaten-Buildern (die selbst Unit-getestet werden sollten, wenn die Logik in ihnen nicht trivial ist). Eine Ausnahme bilden Bibliotheken von Drittanbietern, die im Allgemeinen als "vertrauenswürdig" eingestuft werden und ohne Tests verwendet werden können.
FinnNk
3

Setzen Sie keine Logik in Ihre Unit-Tests ein. Angenommen, Sie testen eine Add-Methode. Sie könnten beispielsweise Folgendes haben:

void MyTest_SaysHello()
{
   string name = "Bob";
   string expected = string.Format("Hello, {0}", name);
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello(name);
   Assert.AreEqual(expected, actual);
}

In diesem speziellen Fall wiederholen Sie wahrscheinlich die gleiche Logik wie im Test. Sie testen also im Wesentlichen "1 + 1 == 1 + 1" und nicht "1 + 1 == 2" "echter" Test. Sie möchten also wirklich, dass Ihr Testcode wie folgt aussieht:

void MyTest_SaysHello()
{
   string expected = "Hello, Bob";
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello("Bob");
   Assert.AreEqual(expected, actual);
}
Hugo
quelle
2
Kleine Korrektur: Ich denke, Sie meinten 'string expected = string.Format ("Hello, Bob")' sollte 'string expected = "Hello, Bob"' sein.
Mike Rosenblum
@MikeRosenblum Sie haben offensichtlich Recht und jemand hat versucht, es zu korrigieren, aber zwei Rezensenten haben diese Änderung abgelehnt
Konrad Morawski
@Konrad: Das ist seltsam. Das ist ein Programmierforum, oder?
Mike Rosenblum
Ich habe die Antwort noch einmal bearbeitet, wie von Mike Rosenblum vorgeschlagen.
BDSL
0

Lange, beschreibende Methodennamen. Denken Sie daran, dass Testmethoden niemals aus Code aufgerufen werden (sie werden vom Unit-Test-Runner aufgerufen, der sie entdeckt und über Reflektion aufruft). Es ist also in Ordnung, verrückt zu werden und Methodennamen mit einer Länge von 50-80 Zeichen zu haben. Eine spezielle Namenskonvention (Groß- und Kleinschreibung, Unterstriche, "sollte", "muss", "wann", "gegeben" usw.) ist nicht wirklich wichtig, solange der Name drei Fragen beantwortet:

  • Was wird getestet?
  • Was sind die Bedingungen?
  • Was ist das erwartete Ergebnis?

Testmethoden sollten kurz sein .

Testmethoden sollten eine einfache, lineare Struktur haben . Nein, wenn oder Schleife Konstrukte.

Testmethoden sollten dem Muster "Anordnen-Handeln-Bestätigen" folgen .

Jeder Test sollte eine Sache prüfen . Dies bedeutet normalerweise eine Aussage pro Test. Ein Test wie { Do A; Assert B; Assert C; }sollte in zwei Teile überarbeitet werden: { Do A; Assert B; }und{ Do A; Assert C; }

Vermeiden Sie zufällige Daten oder Dinge wie "DateTime.Now"

Stellen Sie sicher, dass alle Elemente der Testvorrichtung am Ende des Tests in ihren ursprünglichen Zustand zurückversetzt werden (z. B. durch Abreißen ).

Selbst wenn Sie die Duplizierung in Ihrem Produktionscode rücksichtslos entfernen, ist die Code-Duplizierung in Testvorrichtungen ein viel geringeres Problem.

Azheglov
quelle
-1

Etwas ähnlich dem, was Farmboy bereits erwähnt hat: Mein Methodennamenformat

 <MethodName>Should<actionPerformed>When<Condition>

z.B

 GetBalanceShouldReturnAccountBalance() {
Amit Wadhwa
quelle