Non hai specificato una lingua, quindi cercherò di mantenerla in qualche modo generica. Sarà difficile però, dal momento che è molto più semplice esprimere concetti con codice reale.
Le prove di unità possono essere un po 'di confusione all'inizio. A volte non è sempre chiaro come testare qualcosa o quale sia lo scopo di un test.
Mi piace trattare il test dell'unità come un modo per testare piccoli pezzi di codice.
Il primo posto in cui utilizzo i test di unità è verificare che alcuni metodi funzionino come mi aspetto in tutti i casi. Ho appena scritto un metodo di convalida per un numero di telefono per il mio sito. Accetto qualsiasi input, da 123-555-1212, (123) 555-1212, ecc. Voglio essere sicuro che il mio metodo di validazione funzioni per tutti i possibili formati. Senza un test unitario, sarei obbligato a inserire manualmente ciascun formato diverso e verificare che il modulo sia inserito correttamente. Questo è molto noioso e soggetto a errori. Più tardi, se qualcuno apporta una modifica al codice di convalida del telefono, sarebbe bello se potessimo controllare facilmente per assicurarci che non si rompesse niente altro. (Forse abbiamo aggiunto il supporto per il codice del paese). Quindi, ecco un esempio banale:
public class PhoneValidator
{
public bool IsValid(string phone)
{
return UseSomeRegExToTestPhone(phone);
}
}
ho potuto scrivere uno unit test come questo:
public void TestPhoneValidator()
{
string goodPhone = "(123) 555-1212";
string badPhone = "555 12"
PhoneValidator validator = new PhoneValidator();
Assert.IsTrue(validator.IsValid(goodPhone));
Assert.IsFalse(validator.IsValid(badPhone));
}
Quei 2 linee Assert sarà verificare che il valore restituito da IsValid() è vero e falso, rispettivamente.
Nel mondo reale, probabilmente ci sono molti e molti esempi di numeri di telefono buoni e cattivi. Ho circa 30 numeri di telefono su cui faccio i test. È sufficiente eseguire questo test dell'unità in futuro per sapere se la logica di convalida del telefono è interrotta.
Possiamo anche utilizzare i test di unità per simulare cose al di fuori del nostro controllo.
I test di unità devono essere eseguiti indipendentemente dalle risorse esterne. I test non devono dipendere dalla presenza di un database o dalla disponibilità di un servizio web. Quindi, simuliamo queste risorse, quindi possiamo controllare ciò che restituiscono. Ad esempio, nella mia app, non posso simulare una carta di credito rifiutata al momento della registrazione. Probabilmente la banca non vorrebbe che io inviassi migliaia di carte di credito sbagliate solo per assicurarmi che il mio codice di gestione degli errori fosse corretto. Ecco alcuni esempi di codice:
public class AccountServices
{
private IBankWebService _webService = new BankWebService();
public string RegisterUser(string username, string creditCard)
{
AddUserToDatabase(username);
bool success = _webService.BillUser(creditCard);
if (success == false)
return "Your credit card was declined"
else
return "Success!"
}
}
Questo è dove il test dell'unità è molto confuso e non ovvio. Cosa dovrebbe fare un test di questo metodo? La prima cosa, sarebbe molto bello se potessimo verificare che, se la fatturazione falliva, veniva restituito il messaggio di errore appropriato. Come si scopre, usando una finta, c'è un modo. Usiamo ciò che viene chiamato Inversion of Control. Al momento, AccountServices() è responsabile della creazione dell'oggetto BankWebService.Lasciamo che il chiamante di questa classe fornirle però:
public class AccountServices
{
public AccountServices(IBankWebService webService)
{
_webService = webService;
}
private IBankWebService _webService;
public string RegisterUser(string username, string creditCard)
{
AddUserToDatabase(username);
bool success = _webService.BillUser(creditCard);
if (success == false)
return "Your credit card was declined"
else
return "Success!"
}
}
perché il chiamante è responsabile della creazione dell'oggetto BankWebService, la nostra prova di unità in grado di creare un falso uno:
public class FakeBankWebService : IBankWebService
{
public bool BillUser(string creditCard)
{
return false; // our fake object always says billing failed
}
}
public void TestUserIsRemoved()
{
IBankWebService fakeBank = FakeBankWebService();
AccountServices services = new AccountServices(fakeBank);
string registrationResult = services.RegisterUser("test_username");
Assert.AreEqual("Your credit card was declined", registrationResult);
}
Utilizzando tale oggetto falso , ogni volta che viene chiamato BillUser() della nostra banca, il nostro oggetto falso restituirà sempre false. Il nostro test unitario ora verifica che se la chiamata alla banca fallisce, RegisterUser() restituirà il messaggio di errore corretto.
Supponiamo che un giorno si stanno facendo alcuni cambiamenti, e un bug insinua in: "Successo"
public string RegisterUser(string username, string creditCard)
{
AddUserToDatabase(username);
bool success = _webService.BillUser(creditCard);
if (success) // IT'S BACKWARDS NOW
return "Your credit card was declined"
else
return "Success!"
}
Ora, quando la fatturazione non riesce, il metodo Your RegisterUser() restituisce. Fortunatamente, hai un test unitario scritto. Quel test unitario ora fallirà perché non sta più restituendo "La tua carta di credito è stata rifiutata".
È molto più facile e veloce trovare il bug in questo modo che compilare manualmente il modulo di registrazione con una carta di credito scadente, solo per controllare il messaggio di errore.
Una volta esaminate le diverse strutture di derisione, ci sono cose ancora più potenti che è possibile fare. È possibile verificare i metodi falsi sono stati chiamati, è possibile verificare il numero di volte che è stato chiamato un metodo, è possibile verificare i parametri con cui sono stati chiamati i metodi, ecc.
Penso che una volta comprese queste 2 idee, capirai più che sufficiente per scrivere un sacco di unit test per il tuo progetto.
Se ci dici la lingua che stai utilizzando, possiamo indirizzarti meglio.
Spero che questo aiuti. Mi scuso se parte di esso è fonte di confusione. Lo pulirò se qualcosa non ha senso.
Mi raccomando questa risposta: http://stackoverflow.com/questions/18601/best-practice-for-integrating-tdd-with-web-application-development – Herter
Come ci sono infiniti esempi, questa domanda è troppo ampio – Raedwald