Best Practices für die Benennung von Komponententests [geschlossen]

564

Was sind die Best Practices für die Benennung von Unit-Testklassen und Testmethoden?

Dies wurde bereits in SO unter Was sind einige beliebte Namenskonventionen für Unit-Tests?

Ich weiß nicht, ob dies ein sehr guter Ansatz ist, aber derzeit habe ich in meinen Testprojekten Eins-zu-Eins-Zuordnungen zwischen jeder Produktionsklasse und einer Testklasse, z . B. Productund ProductTest.

In meinen Testklassen habe ich dann Methoden mit den Namen der Methoden, die ich teste, einen Unterstrich und dann die Situation und was ich erwarte, z Save_ShouldThrowExceptionWithNullName().

James Newton-King
quelle
Siehe hier: stackoverflow.com/questions/96297/…
Vergessenes Semikolon
1
Dies beantwortet Ihre Frage nicht, ist aber eine Lektüre wert: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs
3
Im Google Style Guide heißt es: test<MethodUnderTest>_<state>zB testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Methodennamen. Folgen Sie im Zweifelsfall Google.
Ciro Santilli 法轮功 冠状 病 六四 事件 28
2
@CiroSantilli 六四 事件 法轮功 包 包 轩 Und der nächste Satz sagt: "Es gibt keinen richtigen Weg, um Testmethoden zu benennen". Stelle dir das vor.
user2418306
1
Ich bevorzuge auch Jahre später noch Phil Haacks Empfehlung .
Pimbrouwers

Antworten:

524

Ich mag Roy Osheroves Namensstrategie , es ist die folgende:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Es enthält alle Informationen zum Methodennamen und ist strukturiert.

Die Arbeitseinheit kann so klein wie eine einzelne Methode, eine Klasse oder so groß wie mehrere Klassen sein. Es sollte alle Dinge darstellen, die in diesem Testfall getestet werden sollen und unter Kontrolle sind.

Für Assemblys verwende ich die typische .TestsEndung, die meiner Meinung nach ziemlich weit verbreitet ist, und dieselbe für Klassen (Endung mit Tests):

[NameOfTheClassUnderTestTests]

Früher habe ich Fixture als Suffix anstelle von Tests verwendet, aber ich denke, letzteres ist häufiger, dann habe ich die Namensstrategie geändert.

Marc Climent
quelle
228
Für mich macht es keinen Sinn, den Methodennamen in die Testmethode zu setzen. Was ist, wenn Sie die Methode umbenennen? Kein Refactoring-Tool benennt Tests für Sie um. Schließlich benennen Sie Testmethoden von Hand um oder haben mit größerer Wahrscheinlichkeit falsch benannte Tests. Es ist wie mit Kommentaren. Zu viel ist schlimmer als überhaupt keinen Code zu kommentieren.
Piotr Perak
80
@Peri, ich denke es ist ein Kompromiss. Einerseits können Ihre Testnamen veraltet sein, andererseits können Sie nicht sagen, welche Methode Ihr Test testet. Ich finde, dass letzteres viel öfter auftaucht.
Joel McBeth
15
Um Peris Kommentar zu ergänzen: Alle Methoden sind für einige Aktionen verantwortlich, z UpdateManager.Update(). In diesem Sinne neige ich dazu, meine Tests WhenUpdating_State_Behaviouroder zu nennen WhenUpdating_Behaviour_State. Auf diese Weise teste ich eine bestimmte Aktion einer Klasse, ohne einen Methodennamen in einen Testnamen einzufügen. Aber das Wichtigste ist, dass ich eine Ahnung haben muss, welche Geschäftslogik fehlschlägt, wenn ich den Namen eines fehlgeschlagenen Tests
sehe
8
Resharper und IntelliJ würden wahrscheinlich beide Ihre Testmethode finden und anbieten, sie für Sie umzubenennen, wenn Sie sie mit diesen Tools umgestalten / umbenennen. Sie versuchen auch, in Kommentaren nachzuschlagen, in denen Sie den Methodennamen erwähnen, und diese ebenfalls zu aktualisieren.
Jeff Martin
62
Gute Methodennamen sind oft die gleichen wie die Aktion, die die Methode ausführt. Wenn Sie sich zwischen der Benennung Ihres Tests nach Ihrer Methode oder der von der Methode ausgeführten Aktion entscheiden müssen, die möglicherweise ein Hinweis ist, sollten Sie Ihre Methode umbenennen . (Nicht in jedem Fall)
Kaadzia
121

Ich befolge gerne den Namensstandard "Sollte" für Tests, während ich das Testgerät nach dem zu testenden Gerät (dh der Klasse) benenne.

Zur Veranschaulichung (mit C # und NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

Warum "sollte" ?

Ich finde, dass es die Testschreiber zwingt, den Test mit einem Satz zu benennen, der so lautet: "Sollte [in einem Zustand sein] [nach / vor / wann] [Aktion findet statt]".

Ja, das Schreiben von "Sollte" überall wiederholt sich ein wenig, aber wie gesagt, es zwingt die Autoren, richtig zu denken (kann also gut für Anfänger sein). Außerdem führt dies im Allgemeinen zu einem lesbaren englischen Testnamen.

Update :

Mir ist aufgefallen, dass Jimmy Bogard auch ein Fan von "sollte" ist und sogar eine Unit-Test-Bibliothek namens hat Sollte" hat .

Update (4 Jahre später ...)

Für Interessierte hat sich mein Ansatz zur Benennung von Tests im Laufe der Jahre weiterentwickelt. Eines der Probleme mit dem oben beschriebenen Sollte- Muster ist nicht einfach auf einen Blick zu erkennen, welche Methode getestet wird. Für OOP halte ich es für sinnvoller, den Testnamen mit der zu testenden Methode zu beginnen. Für eine gut gestaltete Klasse sollte dies zu lesbaren Testmethodennamen führen. Ich benutze jetzt ein ähnliches Format wie <method>_Should<expected>_When<condition>. Je nach Kontext möchten Sie natürlich die Sollte / Wann-Verben durch etwas Passenderes ersetzen. Beispiel: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Jack Ukleja
quelle
32
Vielleicht sogar noch besser und weniger überflüssig, schreiben Sie einfach einen Satz, der sagt, was er tut, vorausgesetzt, der Test funktioniert : increasesBalanceWhenDepositIsMade().
hotshot309
3
Kürzlich wurde ein Artikel veröffentlicht, in dem eine ähnliche Namenskonvention erwähnt wurde (ich wünschte, ich hätte sie mit einem Lesezeichen versehen). Entwickelt, um die Testlisten gut lesbar zu machen, wenn sie nach Testvorrichtungen sortiert sind. Sie sehen dann etwas wie "BankAccount" darunter (in verschiedenen Zeilen) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made" usw. Liest sich sehr ähnlich wie eine Spezifikation, um die es bei TDD geht.
Simon Tewsi
Den Artikel gefunden. Es ist in Justin Etheredges CodeThinked-Blog Beginning Mocking With Moq 3 - Part 1 .
Simon Tewsi
11
Ich benutze auch Sollte und Wann, aber umgekehrt. zB WhenCustomerDoesNotExist_ShouldThrowException (). Für mich ist dies viel sinnvoller als Sollte dann Wann (dh in einem bestimmten Szenario sollte es ein bestimmtes erwartetes Ergebnis geben). Dies passt auch zu AAA (Arrange, Act, Assert) ... die Assert ist am Ende ... nicht am Anfang ;-)
bytedev
2
@Schneider: unter Berücksichtigung von "sollte" = "empfohlen" dann optional, frage ich mich: Wäre es nicht lexikalisch besser, "soll" = "muss" dann erforderlich / obligatorisch zu verwenden. Zum Beispiel machen RFCs den Unterschied zwischen beiden. Das Bestehen von Tests wird also empfohlen oder ist erforderlich?
Blackwizard
79

Ich mag diesen Namensstil:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

und so weiter. Es macht einem Nicht-Tester wirklich klar, wo das Problem liegt.

Sklivvz
quelle
63
aber @ hotshot309, verwendet er möglicherweise .NET - .NET Capitalization Conventions
Ace
2
@Ace, ich stimme dir vollkommen zu und habe dies ungefähr eine Minute nachdem ich diesen Kommentar gepostet habe bemerkt. Ich habe geschworen, dass ich es gelöscht habe, als ich meinen Fehler sah, aber irgendwie habe ich es wohl nicht getan. Das tut mir leid.
hotshot309
3
@CoffeeAddict, weil Unterstriche innerhalb von Bezeichnern eine <del> Aberration </ del> sind, die in C #
Sklivvz
2
Ich mag auch die Nutzung zu vermeiden , shouldziehe ich werde willsoOrdersWithNoProductsWillFail()
Calin
4
@Calin Meiner Meinung nach Willist die Verwendung nicht wirklich angemessen und damit sagen Sie dem Leser fälschlicherweise, dass der Test in keiner Weise fehlschlagen wird ... wenn Sie Willin Zukunft etwas ausdrücken, das möglicherweise nicht passiert, sind Sie es Wenn Sie es falsch verwenden, Shouldist dies die bessere Wahl, da es anzeigt, dass Sie möchten / möchten, dass etwas passiert, aber es nicht oder nicht konnte. Wenn der Test ausgeführt wird, erfahren Sie, ob es fehlgeschlagen / erfolgreich war, sodass Sie dies nicht wirklich implizieren können vorher, das ist die logische Erklärung dafür, was ist deins? warum vermeidest Shoulddu
Eyal Solnik
51

Kent Beck schlägt vor:

  • Ein Testgerät pro 'Einheit' (Klasse Ihres Programms). Prüfvorrichtungen sind Klassen selbst. Der Name des Testgeräts sollte lauten:

    [name of your 'unit']Tests
    
  • Testfälle (die Testvorrichtungsmethoden) haben folgende Namen:

    test[feature being tested]
    

Zum Beispiel mit der folgenden Klasse:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

Ein Testgerät wäre:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}
Sergio Acosta
quelle
4
Ich wünschte, mehr Menschen würden diesen Richtlinien folgen. Vor nicht allzu langer Zeit musste ich mehr als 20 Testmethoden umbenennen, da sie Namen wie "ATest", "BasicTest" oder "ErrorTest" hatten.
Wedge
85
Wird das Methodenpräfix 'test' angesichts des Suffix der Klasse nicht redundant?
Gavin Miller
50
Denken Sie daran, als Kent dieses Buch schrieb. Attribute wurden nicht erfunden. Daher zeigte der Name Test im Methodennamen dem Testframework an, dass die Methode ein Test war. Auch viel ist seit 2002 passiert.
Thomas Jespersen
14
testCalculateAge ... dies ist ein bedeutungsloser Name für Ihre Testmethode. "test" ist redundant (benennen Sie alle Ihre Methoden mit dem Präfix "method"?). Der Rest des Namens hat keine Bedingung im Test oder was erwartet wurde. Ist CalculateAge die
bytedev
1
Ich möchte hinzufügen, dass bei Verwendung dieser Strategie eine Dokumentation erforderlich ist, um die erwartete Ausgabe anzugeben. Als Randnotiz zum Präfix 'test'; Einige Unit-Test-Frameworks erfordern bestimmte Präfixe oder Suffixe, um die Tests zu erkennen. Das Präfixieren von abstrakten Klassen mit 'Abstract' wird nicht als redundant angesehen (da es sich selbst dokumentiert). Warum gilt das nicht auch für 'Test'?
siebz0r
17

Klassennamen . Bei Namen von Testgeräten finde ich, dass "Test" in der allgegenwärtigen Sprache vieler Domänen weit verbreitet ist. Zum Beispiel in einem technischen Bereich: StressTestund in einem kosmetischen Bereich : SkinTest. Es tut mir leid, Kent nicht zuzustimmen, aber die Verwendung von "Test" in meinen Testgeräten ( StressTestTest?) Ist verwirrend.

"Einheit" wird auch häufig in Domänen verwendet. ZB MeasurementUnit. Wird eine Klasse als MeasurementUnitTestTest von "Measurement" oder "MeasurementUnit" bezeichnet?

Daher verwende ich gerne das Präfix "Qa" für alle meine Testklassen. ZB QaSkinTestund QaMeasurementUnit. Es wird nie mit Domänenobjekten verwechselt, und die Verwendung eines Präfixes anstelle eines Suffix bedeutet, dass alle Testgeräte visuell zusammenleben (nützlich, wenn Sie Fälschungen oder andere Unterstützungsklassen in Ihrem Testprojekt haben).

Namespaces . Ich arbeite in C # und behalte meine Testklassen im selben Namespace wie die Klasse, die sie testen. Dies ist bequemer als separate Test-Namespaces. Natürlich befinden sich die Testklassen in einem anderen Projekt.

Namen der Testmethoden . Ich möchte meine Methoden WhenXXX_ExpectYYY nennen. Es macht die Voraussetzung klar und hilft bei der automatisierten Dokumentation (a la TestDox). Dies ähnelt den Ratschlägen im Google-Testblog, jedoch mit einer stärkeren Trennung von Voraussetzungen und Erwartungen. Zum Beispiel:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory
Grundoon
quelle
Sie haben über Namen von Testmethoden und Testgeräten gesprochen. Die Namen der Testvorrichtungen werden Produktionsklassen zugeordnet. Wo schreiben Sie den Namen der Produktionsmethode in Ihren Test?
Das Licht
12

Ich verwende das Given-When-Then- Konzept. Schauen Sie sich diesen kurzen Artikel an: http://cakebaker.42dh.com/2009/05/28/given-when-then/ . Artikel beschreibt dieses Konzept in Bezug auf BDD, aber Sie können es auch in TDD ohne Änderungen verwenden.

Pashec
quelle
Given-When-Then ist dasselbe wie MethodName_Scenario_ExpectedBehavior, nicht wahr?!
Das Licht
1
Nicht genau. Given_When_Then bezieht sich mehr auf: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Der Test sollte den Willen zum Testen eines Verhaltens ausdrücken, nicht einer Implementierung .
Plog17
1
"Given When Then" wird oft als Gurke bezeichnet. Es ist ein DSL, das aus den Tools Cucumber, JBehave und Behat stammt.
Bytedev
+1 das ist die beste Methode imo. Die Entkopplung, wie eine Methode etwas von dem erwartet, was Sie erwarten, ist sehr leistungsfähig und vermeidet viele Probleme, die in anderen Kommentaren beschrieben werden.
Lee
7

Ich denke, eines der wichtigsten Dinge ist, dass Sie in Ihrer Namenskonvention konsistent sind (und dies mit anderen Mitgliedern Ihres Teams vereinbaren). Zu oft sehe ich viele verschiedene Konventionen, die im selben Projekt verwendet werden.

bytedev
quelle
7

Ich habe kürzlich die folgende Konvention entwickelt, um meine Tests, ihre Klassen und Projekte zu benennen, um ihre Beschreibungen zu maximieren:

Nehmen wir an, ich teste die SettingsKlasse in einem Projekt im MyApp.SerializationNamespace.

Zuerst werde ich ein Testprojekt mit dem MyApp.Serialization.TestsNamespace erstellen .

Innerhalb dieses Projekts und natürlich des Namespace werde ich eine Klasse namens IfSettings(gespeichert als IfSettings.cs ) erstellen .

Nehmen wir an, ich teste die SaveStrings()Methode. -> Ich werde den Test benennen CanSaveStrings().

Wenn ich diesen Test durchführe, wird die folgende Überschrift angezeigt:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Ich denke, das sagt mir sehr gut, was es testet.

Natürlich ist es nützlich, dass das Substantiv "Tests" im Englischen dasselbe ist wie das Verb "tests".

Ihrer Kreativität bei der Benennung der Tests sind keine Grenzen gesetzt, sodass wir vollständige Satzüberschriften für sie erhalten.

Normalerweise müssen die Testnamen mit einem Verb beginnen.

Beispiele beinhalten:

  • Erkennt (zB DetectsInvalidUserInput)
  • Würfe (zB ThrowsOnNotFound)
  • Will (zB WillCloseTheDatabaseAfterTheTransaction)

usw.

Eine andere Möglichkeit ist, "das" anstelle von "wenn" zu verwenden.

Letzteres erspart mir jedoch Tastatureingaben und beschreibt genauer, was ich tue, da ich nicht weiß, dass das getestete Verhalten vorhanden ist, aber teste, ob es vorhanden ist.

[ Bearbeiten ]

Nachdem ich die obige Namenskonvention nun etwas länger verwendet habe, habe ich festgestellt, dass das If- Präfix bei der Arbeit mit Schnittstellen verwirrend sein kann. Es ist einfach so, dass die Testklasse IfSerializer.cs der Schnittstelle ISerializer.cs auf der Registerkarte "Dateien öffnen " sehr ähnlich sieht . Dies kann sehr ärgerlich werden, wenn zwischen den Tests, der getesteten Klasse und ihrer Schnittstelle hin und her gewechselt wird. Als Ergebnis würde ich jetzt That anstelle von If als Präfix wählen .

Zusätzlich verwende ich jetzt - nur für Methoden in meinen Testklassen, da dies nirgendwo anders als Best Practice angesehen wird - das "_", um Wörter in meinen Testmethodennamen wie folgt zu trennen:

[Test] public void detects_invalid_User_Input()

Ich finde das leichter zu lesen.

[ Bearbeiten beenden ]

Ich hoffe, dass dies weitere Ideen hervorbringt, da ich die Benennung von Tests für sehr wichtig halte, da Sie dadurch viel Zeit sparen können, die sonst aufgewendet worden wäre, um zu verstehen, was die Tests tun (z. B. nach Wiederaufnahme eines Projekts nach einer längeren Pause). .

Thorsten Lorenz
quelle
2

In VS + NUnit erstelle ich normalerweise Ordner in meinem Projekt, um Funktionstests zu gruppieren. Dann erstelle ich Unit-Test-Fixture-Klassen und benenne sie nach der Art der Funktionalität, die ich teste. Die [Test] -Methoden sind wie folgt benannt Can_add_user_to_domain:

- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password
Kev
quelle
2

Ich sollte hinzufügen, dass das Speichern Ihrer Tests im selben Paket, aber in einem parallelen Verzeichnis zur getesteten Quelle, das Aufblähen des Codes beseitigt, sobald Sie bereit sind, ihn bereitzustellen, ohne eine Reihe von Ausschlussmustern ausführen zu müssen.

Ich persönlich mag die in "JUnit Pocket Guide" beschriebenen Best Practices ... es ist schwer, ein Buch zu schlagen, das vom Co-Autor von JUnit geschrieben wurde!

Steve Moyer
quelle
3
Glauben Sie nicht, dass dies tatsächlich die vorliegende Frage beantwortet - könnten Sie einen JUnit Pocket Guide bearbeiten und auffrischen? Vielen Dank!
Nate-Wilkins
0

Der Name des Testfalls für die Klasse Foo sollte FooTestCase oder ähnliches sein (FooIntegrationTestCase oder FooAcceptanceTestCase) - da es sich um einen Testfall handelt. Unter http://xunitpatterns.com/ finden Sie einige Standard-Namenskonventionen wie Test, Testfall, Testvorrichtung, Testmethode usw.


quelle