Test delle unità: per iniziare

14

Sto appena iniziando con i test unitari, ma non sono sicuro di capire veramente il punto. Leggo tutorial e libri su tutto, ma ho solo due domande veloci:

  1. Ho pensato che lo scopo del test unitario fosse quello di testare il codice che effettivamente abbiamo scritto. Tuttavia, per me sembra che per essere in grado di eseguire il test, dobbiamo modificare il codice originale, a quel punto non stiamo testando realmente il codice che abbiamo scritto, ma piuttosto il codice che abbiamo scritto per il test.

  2. La maggior parte dei nostri codici si basa su fonti esterne. Tuttavia, dopo il refactoring del nostro codice, anche se rompesse il codice originale, i nostri test funzionerebbero comunque bene, poiché le fonti esterne sono solo muck-up all'interno dei nostri casi di test. Non sconfigge lo scopo del test unitario?

Scusa se sembro stupido qui, ma ho pensato che qualcuno potesse illuminarmi un po '.

Grazie in anticipo.

    
posta treecoder 21.11.2011 - 07:24
fonte

5 risposte

7

My 0.02 $ ... questo è un po 'soggettivo, quindi prendilo con un pizzico di sale, ma spero che ti faccia pensare e / o accendere qualche finestra di dialogo:

  1. Lo scopo principale dei test unitari è di assicurarmi che il codice che hai scritto soddisfa i contratti e i casi limite del tuo codice destinato a soddisfare. Con i test unitari in atto, puoi fare di meglio assicurati che quando tu (o qualcun altro in futuro) i tuoi refactrieri codice, eventuali utenti esterni del tuo codice dovrebbero rimanere inalterati se hai una copertura statale adeguata. (almeno nella misura in cui tu intendi che rimangano inalterati)

    Nella maggior parte dei casi dovresti riuscire a scrivere codice che può entrambi possono essere spediti in produzione ed è facilmente testabile da unità. Una buona il punto di partenza potrebbe essere quello di esaminare i modelli di Iniezione di dipendenza e quadri. (O altre filosofie per la tua lingua / piattaforma di scelta).

  2. È corretto che le implementazioni esterne potrebbero influenzare il tuo codice. Tuttavia assicurando che il codice funzioni correttamente come parte di un più grande il sistema è una funzione del test di integrazione . (Che potrebbe anche essere automatizzato con vari gradi di sforzo).

    Idealmente il tuo codice dovrebbe basarsi solo sui contratti API di qualsiasi 3 ° componenti di partito che significherebbe questo a patto che le tue finte soddisfazioni l'API corretta i tuoi test unitari forniscono ancora valore.

    Detto questo, ammetterò prontamente che ci sono state volte in cui l'ho fatto rinunciare ai test unitari a favore dei soli test di integrazione, ma quello sono stati solo i casi in cui il mio codice ha dovuto interagire così profusamente con Componenti di terze parti con API scarsamente documentate. (cioè il eccezione piuttosto che la regola).

risposta data 21.11.2011 - 07:44
fonte
5
  1. Prova a scrivere prima i test. In questo modo, avrai una solida base per il comportamento del tuo codice e il tuo test diventa un contratto per il comportamento richiesto del tuo codice. Quindi, cambiando il codice per passare il test diventa "cambiando il codice per adempiere al contratto proposto dal test "invece di" cambiare il codice per superare il test ".
  2. Bene, fai attenzione alla differenza tra matrici e mock. Essere non influenzato da eventuali modifiche nel codice è il comportamento caratteristico di mozziconi, ma non deride. Iniziamo con la definizione del mock:

    A Mock object replaces a real object under test conditions, and allows verifying the calls (interactions) against itself as part of a system or unit test.

    -The Art of Unit Testing

In sostanza, i tuoi mock dovrebbero verificare il comportamento richiesto delle tue interazioni. Pertanto, se la tua interazione con il database fallisce dopo un refactoring, anche il tuo test usando la simulazione dovrebbe fallire. Questo ovviamente ha dei limiti, ma con un'attenta pianificazione i tuoi scherzi faranno molto più che "sederti lì" e non "sconfiggeranno lo scopo del test unitario".

    
risposta data 21.11.2011 - 10:16
fonte
1

Fare una buona domanda non è affatto stupido.

Risponderò alle tue domande.

  1. Lo scopo del test unitario non è quello di testare il codice che hai già scritto . Non ha idea del tempo. Solo in TDD dovresti testare prima, ma ciò non si applica rigorosamente a nessun tipo di test unitario. Il punto è essere in grado di testare automaticamente ed efficientemente il tuo programma a livello di classe. Fai quello che devi fare per arrivarci, anche se questo significa cambiare il codice. E lascia che ti dica un segreto - spesso lo dice.
  2. Quando scrivi un test, hai 2 opzioni principali per garantire che il test sia corretto:

    • Varia gli input per ogni test
    • Scrivi un caso di test che assicuri che il tuo programma funzioni correttamente, quindi scrivi un caso di test corrispondente che assicuri che il tuo programma non funzioni come dovrebbe

    Ecco un esempio:

    TEST(MyTest, TwoPlusTwoIsFour) {
        ASSERT_EQ(4, 2+2);
    }
    
    TEST(MyTest, TwoPlusThreeIsntFour) {
        ASSERT_NE(4, 2+3);
    }
    

    Inoltre, se stai testando unitamente la logica all'interno del tuo codice (non le librerie di terze parti), allora è perfettamente bene che tu non ti t preoccuparsi dell'altro codice che si rompe, mentre in quel contesto. Stai essenzialmente testando il modo in cui la logica esegue il wrapping e utilizza le utilità di terze parti, che è uno scenario di test classico.

Una volta che hai finito i test a livello di classe, puoi continuare a testare l'integrazione tra le tue classi (i mediatori, da quello che capisco) e le librerie di terze parti. Questi test sono chiamati test di integrazione e non usano i mock, ma piuttosto le implementazioni concrete di tutte le classi. Sono un po 'più lenti, ma comunque molto importanti!

    
risposta data 22.11.2011 - 09:17
fonte
1

Sembra che tu abbia un'app monolitica che fa tutto in void main() , dall'accesso al database fino alla generazione di output. Ci sono diversi passaggi qui prima che tu possa iniziare il corretto test delle unità.

1) Trova un pezzo di codice che è stato scritto / incollato più volte. Anche se è solo string fullName = firstName + " " + lastName . Spezzala in un metodo, come:

private static string GetFullName (firstName, lastName)
{
    return firstName + " " + lastName;
}

Ora hai una parte di codice testabile per unità, per quanto possa essere banale. Scrivi un unit test per questo. Risciacquare e ripetere questo processo. Alla fine finirai con un carico di metodi raggruppati in modo logico e sarai in grado di estrarre un certo numero di classi da esso. La maggior parte di queste classi sarà testabile.

Come bonus, una volta che hai estratto più classi, puoi estrarre le interfacce da esse e aggiornare il tuo programma per parlare con le interfacce invece degli oggetti stessi. A quel punto, sei in grado di usare un sistema di derisione / stub (o persino i tuoi falsi fatti a mano) senza cambiare il programma. Questo è molto utile una volta che hai estratto le query del database in una classe (o molte) perché ora puoi falsificare i dati che la query dovrebbe restituire.

    
risposta data 22.11.2011 - 17:37
fonte
0

Un ragazzo intelligente ha detto "Se è difficile da testare, probabilmente è un codice errato". Ecco perché non è una brutta cosa riscrivere il codice, per poterlo sbloccare. Il codice con dipendenze esterne è MOLTO DURO da testare, rappresenta un risc il codice, e dovrebbe essere evitato ove possibile, e concentrato nell'integrazione di specifiche aree del tuo codice, fx. classi di tipo facciata / gateway. Ciò renderà molto più facile far fronte a un cambiamento nel componente esterno.

    
risposta data 25.11.2011 - 09:23
fonte

Leggi altre domande sui tag