Standard di codifica per unit test


22

Di solito quando parliamo di standard di codifica ci riferiamo al codice del programma stesso, ma per quanto riguarda i test unitari? Esistono alcune linee guida per gli standard di codifica che sono uniche per i test unitari? Quali sono?

Risposte:


12

Dalla parte superiore della mia testa, posso pensare a tre differenze nello stile di codifica per il codice di test.

Nei metodi di test di denominazione, seguo il modello di shouldDoSomethingWhenSomeConditionHolds.

All'interno del test, è consuetudine seguire il seguente schema di spaziatura:

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

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

    // An assertion follows another blank line.
}

Alcuni insistono su una sola affermazione per test, ma questo è tutt'altro che universale.

Il DRY (Don't Repeat Yourself) è meno importante nel codice di test che nel codice di produzione. Mentre un codice ripetuto dovrebbe essere inserito in un metodo setUp o in una classe testUtils, la ricerca di una ripetizione zero nel codice di test porterà a test strettamente accoppiati e inflessibili, che scoraggiano il refactoring.


Naturalmente, ci sono una varietà di modelli, motivo per cui dovresti fornire anche una risposta.
Eric Wilson,

10
Questo è il modello Arrange, Act, Assert .
Stuper:

DRY è ancora importante. Se è necessario eseguire gli stessi asserimenti in più test, creare una funzione comune e chiamarlo in tutti i test.
MiFreidgeim SO-smetti di essere malvagio il

@MichaelFreidgeim Forse stiamo solo parlando di gradi, ma ho una tolleranza significativamente più alta per la ripetizione nel codice di test. Ho avuto diverse esperienze nella costruzione di suite di test con pochissima ripetizione e ho scoperto che i test sono diventati difficili da modificare e comprendere quando i requisiti sono cambiati. Poi ho smesso di preoccuparmi tanto di DRY nei test e le mie suite di test sono state più facili da usare. <shrug>
Eric Wilson,

16

Roy Osherove raccomanda il seguente modello per nominare i test:

NameOfMethodUnderTest_StateUnderTest_ExpectedBehavior() 

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


Sono d'accordo con Roy. Migliora la leggibilità, anche se ReSharper continua a dirmi che dovrei rimuoverli NameOfMethodUnderTestStateUnderTestExpectedBehavior();)
Oscar Mederos

Come farlo funzionare quando il metodo è sovraccarico, quindi possono esserci più metodi con lo stesso nome?
Narendra Pathai

6

La cosa principale è ricordare che i test unitari sono essenzialmente mini-specifiche. Ciò significa che l'accento deve essere sempre sulla leggibilità.

In primo luogo, ciò significa che i nomi devono comunicare chiaramente ciò che è sotto test e ciò che viene affermato.

In secondo luogo, che a volte viene dimenticato, è che come specifiche dovrebbero fare proprio questo - specificare il comportamento. Cioè, i test unitari non dovrebbero contenere la logica - o potenzialmente cadono nella trappola di ripetere la funzionalità del programma piuttosto che testarla.

A volte i test coinvolgono oggetti che sono complessi da configurare, dovresti cercare di mantenere questa logica di impostazione separata dai tuoi test usando qualcosa come una madre di oggetti o un generatore di dati di test .

Concluderò con alcuni consigli sui libri:

xUnit Test Patterns: Codice di test refactoring: libro eccellente, alcuni dicono che sia un po 'secco ma io non la penso così. Entra in molti dettagli su molti modi diversi di organizzare i test e su come mantenerli sostenibili. Rilevante se stai usando qualcosa come NUnit ecc.

L'arte del test unitario: con esempi in .Net : il miglior libro sul nocciolo della scrittura e del mantenimento dei test. Nonostante sia davvero nuovo, trovo che le sezioni beffarde siano già un po 'datate poiché la sintassi AAA è ora piuttosto standard piuttosto che solo un altro modo di farlo.

Software in crescita orientato agli oggetti, guidato da test : questo libro è semplicemente fantastico! Di gran lunga il miglior libro di test unitari e l'unico avanzato che mette i test unitari come cittadini di prima classe nel processo di progettazione. Stavo leggendo questo quando era una beta pubblica e da allora mi ha raccomandato. Eccellente esempio di realismo reale usato in tutto il libro. Consiglierei comunque di leggere prima il libro di Roy.


IMHO va bene per i test unitari contenere la logica: è perfettamente ragionevole testare una versione altamente ottimizzata ed efficiente di un algoritmo utilizzando un algoritmo ingenuo che fa la stessa cosa per determinare il comportamento corretto. Ad esempio, immagina di testare una tabella hash creando un array associativo basato sulla ricerca lineare.
dsimcha,

2
Sì, ma questo appartiene al di fuori del test nei costruttori di dati di test (che dovrebbero essere testati dall'unità se la logica al loro interno non è banale). Eccezione a ciò sarebbero le librerie di terze parti che in genere sono "fidate" per essere corrette e potrebbero essere utilizzate senza test.
FinnNk,

3

Non mettere la logica nei test delle unità. Ad esempio, supponiamo che stai testando un metodo di aggiunta, potresti avere qualcosa del genere:

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 questo caso particolare, probabilmente stai ripetendo la stessa logica di ciò che è nel test, quindi stai essenzialmente testando "1 + 1 == 1 + 1", anziché "1 + 1 == 2", che è il test "reale". Quindi quello che vorresti davvero fosse il tuo codice di test è:

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

2
Piccola correzione: penso che tu abbia inteso "stringa prevista = stringa. Il formato (" Ciao, Bob ")" dovrebbe essere "stringa prevista =" Ciao, Bob "'.
Mike Rosenblum,

@MikeRosenblum hai ovviamente ragione, e qualcuno ha provato a correggerlo, ma due revisori hanno rifiutato questa modifica
Konrad Morawski,

@Konrad: è strano. Questo è un forum di programmazione, giusto?
Mike Rosenblum,

Ho modificato di nuovo la risposta come suggerito da Mike Rosenblum.
bdsl,

0

Nomi di metodi lunghi e descrittivi. Ricorda, i metodi di test non vengono mai chiamati dal codice (vengono chiamati dal runner del test unità che li scopre e li chiama tramite reflection), quindi va bene impazzire e avere nomi di metodi lunghi 50-80 caratteri. La convenzione di denominazione specifica (caso cammello, caratteri di sottolineatura, "dovrebbe", "deve", "quando", "dato", ecc.) Non è davvero importante fintanto che il nome risponde a tre domande:

  • cosa è sotto test?
  • quali sono le condizioni?
  • Qual è il risultato atteso?

I metodi di prova dovrebbero essere brevi .

I metodi di prova dovrebbero avere una struttura semplice e lineare . Nessun costrutto if o loop.

I metodi di prova dovrebbero seguire il modello "dispos-act-assert" .

Ogni test dovrebbe testare una cosa . Questo di solito significa un'affermazione per test. Un test come { Do A; Assert B; Assert C; }dovrebbe essere riformulato in due: { Do A; Assert B; }e{ Do A; Assert C; }

Evita dati casuali o cose come 'DateTime.Now'

Accertarsi che tutti i componenti del dispositivo di prova siano riportati allo stato originale alla fine del test (ad es. Utilizzando uno smontaggio )

Anche se si rimuove la duplicazione spietatamente dal codice di produzione, la duplicazione del codice nei dispositivi di prova è una preoccupazione molto più piccola.


-1

Un po 'simile a quello che Farmboy ha già menzionato, Il mio formato del nome del metodo

 <MethodName>Should<actionPerformed>When<Condition>

per esempio

 GetBalanceShouldReturnAccountBalance() {
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.