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 sugli standard di codifica che sono esclusive dei 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 sugli standard di codifica che sono esclusive dei test unitari? Quali sono?
In cima alla 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 asserzione per test, ma questo è tutt'altro che universale.
Il DRY (Do not Repeat Yourself) è meno importante nel codice di test che nel codice di produzione. Mentre alcuni codici ripetuti devono essere inseriti in un metodo setUp o in una classe testUtils, il tentativo di azzerare la ripetizione nel codice di test porterà a test strettamente accoppiati e inflessibili, il che scoraggia il refactoring.
La cosa principale è ricordare che i test unitari sono essenzialmente mini-specifiche. Ciò significa che l'accento deve sempre essere 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, tuttavia, che a volte viene dimenticato, è che le specifiche dovrebbero fare proprio questo: specificare il comportamento. Cioè, i test unitari non dovrebbero contenere la logica - o potenzialmente cadranno nella trappola di ripetere la funzionalità del programma piuttosto che testarla.
A volte i test coinvolgeranno oggetti che sono complessi da configurare, dovresti sforzarti di mantenere questa logica di configurazione separata dai tuoi test usando qualcosa come oggetto madre o costruttore di dati di test .
Concludo con alcuni consigli sui libri:
xTest di test di identità: codice test di refactoring: libro eccellente, alcuni dicono che è un po 'secco ma non lo faccio Penso di sì. Fornisce molti dettagli su molti modi diversi di organizzare i test e su come mantenerli mantenibili. Rilevante se stai usando qualcosa come NUnit ecc.
The Art of Unit Test: con esempi in .Net : il miglior libro sul nitty-grinty di scrivere e mantenere i test. Nonostante sia davvero nuovo, trovo le sezioni di derisione un po 'datate, dato che la sintassi AAA ora è piuttosto standard piuttosto che un altro modo di farlo.
Crescere il software orientato agli oggetti, guidato dai test : questo libro è semplicemente fantastico! Di gran lunga il miglior libro di test unitario e l'unico avanzato che mette il test unitario come cittadino di prima classe nel processo di progettazione. Stavo leggendo questo quando era una beta pubblica e lo raccomandavo da allora. Eccellente esempio di lavoro reale utilizzato in tutto il libro. Consiglierei comunque di leggere il libro di Roy prima.
Non inserire la logica nei test dell'unità. Ad esempio, supponiamo che stai testando un metodo di aggiunta, potresti avere qualcosa di simile a questo:
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", piuttosto che "1 + 1 == 2", che è il "vero" test. Quindi quello che vorresti fosse il tuo codice di prova è:
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 che i metodi di test non vengono mai richiamati dal codice (vengono chiamati dall'unità di test runner che li rileva e li chiama tramite la reflection), quindi va bene impazzire e hanno nomi di metodi lunghi 50-80 caratteri. Convenzione di denominazione specifica (cammello-caso, underscore, "dovrebbe", "deve", "quando", "dato", ecc.) Non è veramente importante purché il nome risponda a tre domande:
I metodi di test 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 lo schema "organizza-act-assert" .
Ogni test dovrebbe testare una cosa . Questo di solito significa un assert per test. Un test come { Do A; Assert B; Assert C; }
dovrebbe essere refactored in due: { Do A; Assert B; }
e { Do A; Assert C; }
Evita dati casuali o cose come "DateTime.Now"
Assicurati che tutti i membri del dispositivo di prova siano riportati al loro stato originale alla fine del test (ad esempio utilizzando un teardown )
Anche se rimuovi la duplicazione spietatamente nel tuo codice di produzione, la duplicazione del codice nei dispositivi di prova è un problema molto più piccolo.
Un po 'simile a quello che Farmboy ha già menzionato, Il mio formato del nome del metodo
<MethodName>Should<actionPerformed>When<Condition>
es
GetBalanceShouldReturnAccountBalance() {
Leggi altre domande sui tag unit-testing coding-standards