Unit-Test benennt Best Practices

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

Dies wurde zuvor in SO diskutiert. Unter Was sind einige beliebte Namenskonventionen für Komponententests?

Ich weiß nicht, ob das ein sehr guter Ansatz ist, aber momentan habe ich in meinen Testprojekten Eins-zu-eins-Zuordnungen zwischen jeder Produktionsklasse und einer ProductTest , zB Product und ProductTest .

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

   

Ich mag Roy Osheroves Benennungsstrategie , das ist das Folgende:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Es enthält alle Informationen, die für den Methodennamen benötigt werden, und in einer strukturierten Weise.

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

Für Assemblies verwende ich die typische .Tests Endung, die meiner Meinung nach ziemlich weit verbreitet ist und die gleiche für classn (endet mit Tests ):

[NameOfTheClassUnderTestTests]

Früher habe ich Fixture als Suffix anstelle von Tests verwendet, aber ich denke, Letzteres ist häufiger, dann änderte ich die Benennungsstrategie.

Ich folge gerne dem “Should” -Benennungsstandard für Tests, während ich das Testgerät nach dem Testobjekt benenne (dh der class).

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 Testautoren dazu zwingt, den Test mit einem Satz nach dem Motto “Sollte [in / in / in / wann / wann] [Aktion findet statt]” zu benennen.

Ja, das Schreiben von “Sollte” wird überall ein wenig repetitiv, aber wie ich schon sagte, zwingt es Schriftsteller dazu, richtig zu denken (das kann gut für Anfänger sein). Außerdem führt dies in der Regel zu einem lesbaren englischen Testnamen.

Aktualisierung :

Ich habe bemerkt, dass Jimmy Bogard auch ein Fan von “sollte” ist und sogar eine Unit-Test-Bibliothek namens Should 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 Should- Muster, das ich oben beschrieben habe, ist nicht leicht zu erkennen, welche Methode gerade getestet wird. Für OOP halte ich es für sinnvoller, den Testnamen mit der zu testenden Methode zu starten. Für eine gut gestaltete class sollte dies zu lesbaren Namen der Testmethode führen. Ich benutze jetzt ein Format ähnlich wie _Should_When . Abhängig vom Kontext möchten Sie vielleicht die Soll / Wenn-Verben für etwas passenderes ersetzen. Beispiel: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Ich mag diesen Namensstil:

 OrdersShouldBeCreated(); OrdersWithNoProductsShouldFail(); 

und so weiter. Es macht einem Nicht-Tester klar, was das Problem ist.

Kent Beck schlägt vor:

  • Ein Testgerät pro Einheit (class Ihres Programms). Testleuchten sind selbst classn. Der Name des Testgeräts sollte lauten:

     [name of your 'unit']Tests 
  • Testfälle (die Test-Fixture-Methoden) haben Namen wie:

     test[feature being tested] 

Zum Beispiel mit der folgenden class:

 class Person { int calculateAge() { ... } // other methods and properties } 

Eine Testvorrichtung wäre:

 class PersonTests { testAgeCalculationWithNoBirthDate() { ... } // or testCalculateAge() { ... } } 

classnnamen . Für Test-Fixture-Namen finde ich, dass “Test” in der allgegenwärtigen Sprache vieler Domänen recht häufig vorkommt. Zum Beispiel in einer Engineering-Domäne: StressTest und in einer Kosmetik-Domäne: SkinTest . Tut mir leid, Kent nicht StressTestTest , aber die Verwendung von “Test” in meinen Testgeräten ( StressTestTest ?) StressTestTest verwirrend.

“Unit” wird auch häufig in Domains verwendet. ZB MeasurementUnit . Ist eine class namens MeasurementUnitTest ein Test von “Measurement” oder “MeasurementUnit”?

Daher verwende ich gerne das Präfix “Qa” für alle meine Testklassen. ZB QaSkinTest und QaMeasurementUnit . Es wird niemals mit Domänenobjekten verwechselt, und die Verwendung eines Präfixes anstelle eines Suffix bedeutet, dass alle Testeinrichtungen visuell zusammen leben (nützlich, wenn Sie Fälschungen oder andere Supportklassen in Ihrem Testprojekt haben).

Namespaces . Ich arbeite in C # und ich halte meine Testklassen im selben Namespace wie die class, die sie testen. Es ist bequemer als separate Testnamespaces. Natürlich sind die Testklassen in einem anderen Projekt.

Test Methodennamen . Ich möchte meine Methoden WhenXXX_ExpectYYY nennen. Es macht die Voraussetzung klar und hilft bei der automatisierten Dokumentation (a la TestDox). Dies ähnelt dem Hinweis auf dem Google-Testblog, jedoch mit einer größeren Trennung von Voraussetzungen und Erwartungen. Beispielsweise:

 WhenDivisorIsNonZero_ExpectDivisionResult WhenDivisorIsZero_ExpectError WhenInventoryIsBelowOrderQty_ExpectBackOrder WhenInventoryIsAboveOrderQty_ExpectReducedInventory 

Siehe: http://googeltesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

Für Testmethoden-Namen finde ich persönlich die Verwendung von ausführlichen und selbst-dokumentierten Namen sehr nützlich (neben Javadoc-Kommentaren, die weiter erklären, was der Test macht).

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

Angenommen, ich teste die class ” Einstellungen” in einem Projekt im MyApp.Serialization- Namespace.

Zuerst erstelle ich ein Testprojekt mit dem Namensraum MyApp.Serialization.Tests .

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

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

Wenn ich diesen Test durchführe, wird 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 im Englischen das Substantiv “Tests” dasselbe ist wie das Verb “Tests”.

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

Normalerweise müssen die Testnamen mit einem Verb beginnen.

Beispiele beinhalten:

  • Erkennt (zB DetectsInvalidUserInput)
  • Wirft (zB ThrowsOnNotFound)
  • Will (zB WillCloseTheDatabaseAfterTheTransaction)

etc.

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

Letzteres erspart mir Tastenanschläge und beschreibt genauer, was ich mache, da ich nicht weiß, dass das getestete Verhalten vorhanden ist, aber wenn es getestet wird.

[ Bearbeiten ]

Nachdem ich die obige Benennungskonvention jetzt etwas länger verwendet habe, habe ich festgestellt, dass das If- Präfix beim Arbeiten mit Interfaces verwirrend sein kann. Es ist einfach so, dass die Test-class IfSerializer.cs der Schnittstelle ISerializer.cs im “Open Files Tab” sehr ähnlich sieht. Dies kann sehr nervig werden, wenn zwischen den Tests, der getesteten class und der Schnittstelle hin und her geschaltet wird. Als Ergebnis würde ich jetzt That over If als Präfix wählen.

Zusätzlich verwende ich jetzt – nur für Methoden in meinen Testklassen, da es nirgendwo anders als Best Practice gilt – das “_”, um Wörter in meinen Test Methodennamen zu trennen, wie in:

  • [Test] öffentlich void detects_invalid_User_Input () *

Ich finde das leichter zu lesen.

[ Bearbeiten beenden ]

Ich hoffe, dass dies zu weiteren Ideen führt, da ich die Benennung von Tests als sehr wichtig erachte, da es Ihnen viel Zeit ersparen kann, die sonst aufgewendet hätte, um zu verstehen, was die Tests machen (zB nach einer längeren Pause). .

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

Ich denke, eines der wichtigsten Dinge ist, in Ihrer Namenskonvention konsistent zu sein (und sie mit anderen Mitgliedern Ihres Teams zu vereinbaren). Zu oft sehe ich viele verschiedene Konventionen in einem Projekt.

In VS + NUnit erstelle ich normalerweise Ordner in meinem Projekt, um functionstests zu gruppieren. Dann erstelle ich Unit-Test-Fixture-classn und benenne sie nach dem Typ der functionalität, die ich gerade teste. Die [Test] -Methoden werden in der Zeile 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 

Ich sollte hinzufügen, dass das Beibehalten Ihrer Tests in demselben Paket, aber in einem parallelen Verzeichnis zu der Quelle, die getestet wird, das Aufblähen des Codes beseitigt, sobald Sie bereit sind, es bereitzustellen, ohne eine Reihe von Ausschlussmustern auszuführen.

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!

Der Name des Testfalls für class Foo sollte FooTestCase oder etwas ähnliches sein (FooIntegrationTestCase oder FooAcceptanceTestCase) – da es sich um einen Testfall handelt. Siehe http://xunitpatterns.com/ für einige Standardnamenskonventionen wie Test, Testfall, Testvorrichtung, Testmethode usw.