Best practice per la denominazione di unit test [chiuso]


564

Quali sono le migliori pratiche per la denominazione di classi di test unit e metodi di test?

Questo è stato discusso su SO prima, in Quali sono alcune convenzioni di denominazione popolari per i test unitari?

Non so se si tratta di un approccio molto valido, ma attualmente nei miei progetti di test ho mappature one-to-one tra ciascuna classe di produzione e una classe di test, ad esempio Producte ProductTest.

Nelle mie classi di test ho quindi metodi con i nomi dei metodi che sto testando, un trattino basso, quindi la situazione e ciò che mi aspetto che accada, ad es Save_ShouldThrowExceptionWithNullName().



1
Questo non risponde alla tua domanda, ma merita una lettura: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs

3
La guida di stile di Google dice: test<MethodUnderTest>_<state>ad esempio testPop_emptyStack google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Nomi dei metodi. In caso di dubbi, segui Google.
Ciro Santilli 28 冠状 病 六四 事件 法轮功

2
@CiroSantilli 六四 事件 法轮功 包 卓 轩 E la frase successiva dice: "Non esiste un modo corretto per nominare i metodi di prova". Vai a capire.
user2418306,

1
Preferisco ancora la raccomandazione di Phil Haack anche anni dopo.
pimbrouwers,

Risposte:


524

Mi piace la strategia di denominazione di Roy Osherove , è la seguente:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Ha tutte le informazioni necessarie sul nome del metodo e in modo strutturato.

L'unità di lavoro può essere piccola come un singolo metodo, una classe o grande come più classi. Dovrebbe rappresentare tutte le cose che devono essere testate in questo caso di test e che sono sotto controllo.

Per gli assiemi uso il .Testsfinale tipico , che penso sia abbastanza diffuso e lo stesso per le classi (che termina con Tests):

[NameOfTheClassUnderTestTests]

In precedenza ho usato Fixture come suffisso anziché Test, ma penso che quest'ultimo sia più comune, quindi ho cambiato la strategia di denominazione.


228
Per me non ha senso inserire il nome del metodo nel metodo di prova. Cosa succede se si rinomina il metodo? Nessuno strumento di refactoring rinominerà i test per te. Alla fine si finisce per rinominare i metodi di test a mano o più probabilmente con test sbagliati. È come con i commenti. Troppo è peggio quindi non commentare affatto il codice.
Piotr Perak,

80
@Peri, penso che sia un compromesso. Da un lato i nomi dei tuoi test potrebbero diventare obsoleti, dall'altro non puoi dire quale metodo sta testando. Trovo che quest'ultimo arrivi molto più spesso.
Joel McBeth,

15
Per aggiungere al commento di Peri, tutti i metodi sono responsabili di alcune azioni, ad es UpdateManager.Update(). Avendo questo in mente, tendo a chiamare i miei test WhenUpdating_State_Behaviouro WhenUpdating_Behaviour_State. In questo modo testare una particolare azione di una classe evitando di inserire un nome metodo in un nome test. Ma la cosa più importante è che devo avere un'idea di quale logica aziendale stia fallendo quando vedo il nome di un test fallito
Ramunas,

8
Resharper e IntelliJ probabilmente troverebbero il tuo metodo di prova e si offriranno di rinominarlo per te se lo refactoring / rinominato usando quegli strumenti. Prova anche a guardare nei commenti in cui menzioni il nome del metodo e aggiorni anche quelli.
Jeff Martin,

62
I nomi di buoni metodi spesso sono gli stessi dell'azione compiuta dal metodo. Se devi decidere tra la denominazione del test dopo il metodo o l'azione eseguita dal metodo che potrebbe essere un suggerimento, dovresti rinominare il metodo . (Non in ogni caso però)
Kaadzia,

121

Mi piace seguire lo standard di denominazione "Dovrebbe" per i test mentre nomina l' apparecchiatura di test dopo l'unità sotto test (cioè la classe).

Per illustrare (usando C # e 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));
  }
}

Perché "dovrebbe" ?

Trovo che costringe gli autori del test a nominare il test con una frase lungo le righe di "Dovrebbe [essere in qualche stato] [dopo / prima / quando] [l'azione ha luogo]"

Sì, scrivere "Dovrei" ovunque diventa un po 'ripetitivo, ma come ho detto costringe gli scrittori a pensare nel modo corretto (quindi può essere buono per i principianti). Inoltre, in genere si ottiene un nome test inglese leggibile.

Aggiornamento :

Ho notato che Jimmy Bogard è anche un fan di "should" e ha persino una libreria di test unitari chiamata Should .

Aggiornamento (4 anni dopo ...)

Per coloro che sono interessati, il mio approccio ai test di denominazione si è evoluto nel corso degli anni. Uno dei problemi con il modello Should che ho descritto sopra non è facile sapere a colpo d'occhio quale metodo è in fase di test. Per OOP penso che abbia più senso iniziare il nome del test con il metodo in esame. Per una classe ben progettata ciò dovrebbe tradursi in nomi di metodi di prova leggibili. Ora uso un formato simile a <method>_Should<expected>_When<condition>. Ovviamente, a seconda del contesto, potresti voler sostituire i verbi Should / When con qualcosa di più appropriato. Esempio: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()


32
Forse anche meglio e meno ridondante, basta scrivere una frase che dice ciò che fa, assumendo le opere di prova: increasesBalanceWhenDepositIsMade().
hotshot309

3
Recentemente ho visto un articolo che menzionava una convenzione di denominazione simile (vorrei averla aggiunta ai segnalibri). Progettato per rendere molto leggibili gli elenchi dei test ordinati in base al dispositivo di test. Vedrai qualcosa di simile a "BankAccount" sotto di esso (su righe diverse) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made", ecc. Legge come una specifica, che è una specie di TDD.
Simon Tewsi,

Ho trovato l'articolo. È nel blog CodeThinked di Justin Etheredge che inizia a deridere con Moq 3 - Parte 1 .
Simon Tewsi,

11
Uso anche Should and When ma viceversa. ad es. WhenCustomerDoesNotExist_ShouldThrowException (). Per me questo ha molto più senso di Dovrebbe allora Quando (cioè in un certo scenario dovrebbe esserci un certo risultato atteso). Questo si adatta anche con AAA (Arrange, Act, Assert) ... l'Assert è alla fine ... non l'inizio ;-)
bytedev

2
@Schneider: considerando "dovrebbe" = "raccomandato" quindi facoltativo, mi chiedo: non sarebbe lessicalmente meglio usare "deve" = "deve" quindi richiesto / obbligatorio. Ad esempio, gli RFC fanno la differenza tra entrambi. Quindi è consigliato o richiesto il superamento dei test?
blackwizard,

79

Mi piace questo stile di denominazione:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

e così via. Rende davvero chiaro a un non tester quale sia il problema.


63
ma @ hotshot309, potrebbe usare .NET - Convenzioni di capitalizzazione .NET
Ace

2
@Ace, sono totalmente d'accordo con te e l'ho notato circa un minuto dopo aver pubblicato questo commento. Ho giurato di averlo eliminato quando ho visto il mio errore, ma in qualche modo, immagino di no. Mi dispiace per quello.
hotshot309

3
@CoffeeAddict perché i caratteri di sottolineatura all'interno degli identificatori sono un <del> aberrazione </del> non proprio idiomatico in C #
Sklivvz,

2
Mi piace anche evitare l'uso di shouldpreferirò willcosìOrdersWithNoProductsWillFail()
Calin,

4
@Calin Secondo me l'uso Willnon è proprio appropriato e, facendo così, in realtà stai erroneamente dicendo al lettore che in nessun modo il test fallirà ... se usi Willper esprimere qualcosa in futuro che potrebbe non accadere, sei usarlo in modo errato mentre Shouldè la scelta migliore qui perché indica che vuoi / desideri che qualcosa accada ma non è successo o no, quando il test viene eseguito ti dice se ha fallito / è riuscito, quindi non puoi davvero sottintendere che in anticipo, questa è la spiegazione logica ad esso, qual è la tua? perché eviti Should?
Eyal Solnik,

51

Kent Beck suggerisce:

  • Un dispositivo di prova per "unità" (classe del programma). Le apparecchiature di prova sono le classi stesse. Il nome del dispositivo di prova dovrebbe essere:

    [name of your 'unit']Tests
    
  • I casi di test (i metodi del dispositivo di prova) hanno nomi come:

    test[feature being tested]
    

Ad esempio, con la seguente classe:

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

    // other methods and properties
}

Un dispositivo di prova sarebbe:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

4
Vorrei che più persone seguissero queste linee guida. Non molto tempo fa ho dovuto rinominare più di 20 metodi di test perché avevano nomi come "ATest", "BasicTest" o "ErrorTest".
Wed

85
il prefisso del metodo di 'test' non diventa ridondante dato il suffisso della classe?
Gavin Miller,

50
Ricorda che quando Kent ha scritto quel libro. Gli attributi non sono stati inventati. Pertanto il nome Test nel nome del metodo indicava al framework di test che il metodo era un test. Anche molti sono successi dal 2002.
Thomas Jespersen,

14
testCalculateAge ... questo è un nome senza significato per il tuo metodo di test. "test" è ridondante (denominate tutti i metodi con il prefisso "method"?). Il resto del nome non ha alcuna condizione sotto test o ciò che era previsto. CalculateAge è il metodo in esame? ..... chissà ...
byev,

1
Vorrei aggiungere che quando si utilizza questa strategia, è necessaria la documentazione per specificare l'output previsto. Come nota a margine sul prefisso "test"; alcuni framework di unit test richiedono prefissi o suffissi specifici per riconoscere i test. Il prefisso delle classi astratte con 'Abstract' non è considerato ridondante (perché è auto-documentante), quindi perché lo stesso non si applica con 'Test'?
siebz0r,

17

Nomi delle classi . Per i nomi dei dispositivi di prova, trovo che "Test" sia abbastanza comune nel linguaggio onnipresente di molti domini. Ad esempio, in un dominio di ingegneria: StressTeste in un dominio cosmetici: SkinTest. Mi dispiace non essere d'accordo con Kent, ma usare "Test" nei miei dispositivi di prova ( StressTestTest?) È confuso.

"Unità" è anche molto usata nei domini. Es MeasurementUnit. Una classe è chiamata MeasurementUnitTesttest di "Measurement" o "MeasurementUnit"?

Pertanto mi piace usare il prefisso "Qa" per tutte le mie classi di test. Ad esempio, QaSkinTeste QaMeasurementUnit. Non viene mai confuso con gli oggetti di dominio e l'utilizzo di un prefisso anziché di un suffisso significa che tutte le apparecchiature di test convivono visivamente (utile se nel progetto di test sono presenti falsi o altre classi di supporto)

Spazi dei nomi . Lavoro in C # e mantengo le mie classi di test nello stesso spazio dei nomi della classe che stanno testando. È più conveniente che avere spazi dei nomi di prova separati. Naturalmente, le classi di test fanno parte di un progetto diverso.

Nomi dei metodi di prova . Mi piace nominare i miei metodi WhenXXX_ExpectYYY. Rende chiara la precondizione e aiuta con la documentazione automatizzata (alla TestDox). Questo è simile ai consigli sul blog di test di Google, ma con una maggiore separazione di condizioni e aspettative. Per esempio:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

hai parlato dei nomi dei metodi di prova e dei nomi dei dispositivi di prova. i nomi degli apparecchi di prova sono associati alle classi di produzione. dove scrivi il nome del metodo di produzione nel tuo test?
The Light,

12

Uso il concetto Given-When-Then . Dai un'occhiata a questo breve articolo http://cakebaker.42dh.com/2009/05/28/given-when-then/ . L'articolo descrive questo concetto in termini di BDD, ma è possibile utilizzarlo anche in TDD senza alcuna modifica.


Given-When-Then è uguale a MethodName_Scenario_ExpectedBehavior, vero ?!
The Light,

1
Non esattamente. Given_When_Then si riferisce più a: GivenAnEntity_WhenSomeActionHappens_ThatResultIsExpected Il test dovrebbe esprimere la volontà di testare un comportamento e non un'implementazione .
plog17,

1
"Dato quando allora" viene spesso definito cetriolino. È un DSL che è uscito dagli strumenti Cucumber, JBehave e Behat.
bytedev

+1 questo è il metodo migliore imo. Il disaccoppiamento di come un metodo fa qualcosa da quello che ti aspetti sia il risultato è molto potente ed evita molti problemi descritti in altri commenti.
Lee,


7

Penso che una delle cose più importanti sia quella di essere coerenti nella tua convenzione di denominazione (e concordarla con gli altri membri della tua squadra). Molte volte vedo un sacco di convenzioni diverse utilizzate nello stesso progetto.


7

Di recente ho escogitato la seguente convenzione per nominare i miei test, le loro classi e contenere i progetti al fine di massimizzarne le descrizioni:

Diciamo che sto testando la Settingsclasse in un progetto nello MyApp.Serializationspazio dei nomi.

Per prima cosa creerò un progetto di test con lo MyApp.Serialization.Testsspazio dei nomi.

All'interno di questo progetto e ovviamente lo spazio dei nomi creerò una classe chiamata IfSettings(salvata come IfSettings.cs ).

Diciamo che sto testando il SaveStrings()metodo. -> Chiamerò il test CanSaveStrings().

Quando eseguo questo test mostrerà la seguente intestazione:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Penso che questo mi dica molto bene, cosa sta testando.

Naturalmente è utile che in inglese il nome "Test" sia lo stesso del verbo "test".

Non c'è limite alla tua creatività nel nominare i test, in modo da ottenere titoli completi per loro.

Di solito i nomi dei test dovranno iniziare con un verbo.

Esempi inclusi:

  • Rileva (ad es. DetectsInvalidUserInput)
  • Lancia (es. ThrowsOnNotFound)
  • Volontà (ad es. WillCloseTheDatabaseAfterTheTransaction)

eccetera.

Un'altra opzione è quella di utilizzare "that" invece di "if".

Quest'ultimo però mi salva la pressione dei tasti e descrive più esattamente cosa sto facendo, poiché non lo so, che il comportamento testato è presente, ma sto testando se lo è.

[ Modifica ]

Dopo aver usato la convenzione di denominazione sopra per un po 'di più, ho scoperto che il prefisso If può essere fonte di confusione, quando si lavora con le interfacce. Accade semplicemente che la classe di test IfSerializer.cs sia molto simile all'interfaccia ISerializer.cs nella "Scheda File aperti". Questo può diventare molto fastidioso quando si passa avanti e indietro tra i test, la classe in fase di test e la sua interfaccia. Di conseguenza ora sceglierei Quello su Se come prefisso.

Inoltre ora uso - solo per i metodi nelle mie classi di test in quanto non è considerata la migliore pratica altrove - il "_" per separare le parole nei nomi dei miei metodi di prova come in:

[Test] public void detects_invalid_User_Input()

Trovo che sia più facile da leggere.

[ Fine modifica ]

Spero che questo generi altre idee, dal momento che considero test di denominazione di grande importanza in quanto può farti risparmiare un sacco di tempo che altrimenti sarebbe stato speso cercando di capire cosa stanno facendo i test (ad esempio dopo aver ripreso un progetto dopo una pausa prolungata) .


2

In VS + NUnit di solito creo cartelle nel mio progetto per raggruppare test funzionali. Quindi creo le classi di dispositivi di unit test e le denomino in base al tipo di funzionalità che sto testando. I metodi [Test] sono denominati secondo le linee di 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

2

Dovrei aggiungere che il mantenimento dei test nello stesso pacchetto, ma in una directory parallela alla sorgente in fase di test, elimina il gonfiore del codice una volta che sei pronto a distribuirlo senza dover fare un mucchio di schemi di esclusione.

Personalmente mi piacciono le migliori pratiche descritte nella "Guida tascabile di JUnit" ... è difficile battere un libro scritto dal coautore di JUnit!


3
Non credete che questo risponda effettivamente alla domanda a portata di mano: potreste fare una modifica e fare riferimento a JUnit Pocket Guide? Grazie!
Nate-Wilkins,

0

il nome del test case per la classe Foo dovrebbe essere FooTestCase o qualcosa del genere (FooIntegrationTestCase o FooAcceptanceTestCase), poiché si tratta di un caso di test. consultare http://xunitpatterns.com/ per alcune convenzioni di denominazione standard come test, caso di test, dispositivo di test, metodo di test, ecc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.