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?
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:
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.
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
NameOfMethodUnderTestStateUnderTestExpectedBehavior()
;)
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.
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);
}
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:
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.
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() {