È considerato "cattiva pratica" controllare il contenuto del file / la codifica nei test unitari?

84

Un po 'di contesto: prima di oggi dovevo aggiornare del codice SQL fornito da un altro mio collega, e dato che è uno script piuttosto grande, è archiviato come un file separato (che viene poi letto ed eseguito in fase di runtime). Mentre lo facevo, ho reintrodotto per errore due bug che avevamo qualche mese fa, ovvero:

  • Per qualsiasi motivo il file ASCII è stato codificato in UTF-16 (il collega mi ha inviato via email il file, che potrebbe averlo causato).
  • Lo script mancava delle istruzioni iniziali SET (richieste a causa di alcuni fattori di produzione in fase di produzione, ma non su un'installazione pulita localmente).

Dopo aver eseguito il debugging per circa un'ora (di nuovo), ho deciso di scrivere alcuni test unitari per garantire che ciò non si ripetesse mai più (e includere un modo rapido per risolverlo nel messaggio di asserzione per fornire una soluzione semplice per gli sviluppatori futuri).

Tuttavia, quando ho spinto questo codice, un altro collega (che è anche il nostro team leader) si avvicina a me e mi ha detto che non dovrei fare di nuovo queste cose perché:

"These things don't belong in unit tests"

"Unit tests should only be used to check the flow of your code"

Ora sono piuttosto conflittuale dal momento che continuo a pensare che quello che sto facendo non sia sbagliato, visto che questo bug non verrà reintrodotto in futuro, tuttavia questo collega lavora come senior e alla fine della giornata per decidere su cosa passiamo il nostro tempo. Cosa dovrei fare? Ho sbagliato a farlo in questo modo? È considerato una cattiva pratica?

    
posta Paradoxis 30.10.2017 - 19:57
fonte

12 risposte

156

Molto probabilmente i test che hai scritto sono più vicini ai test di integrazione o di regressione rispetto ai test unitari. Mentre la linea può essere molto confusa ea volte devoluta in pedanteria su quello che è o non è un test unitario, vorrei tornare dal tuo collega e chiedere dove dovrebbero essere i test che hai scritto dato che aggiungono valore assicurando la correttezza del codice.

Non mi concentrerei molto su ciò che è o non è un test unitario e mi rendo conto che anche se è un test di integrazione, potrebbe esserci ancora un valore nel test.

    
risposta data 30.10.2017 - 20:07
fonte
36

Tecnicamente, non si tratta di un test unitario e più di un passo di convalida. L'approccio corretto dipende in realtà da cosa deve essere il tuo flusso di lavoro. Il tuo team lead è corretto su quale sia lo scopo dei test unitari. La mia sensazione è che questo è un caso di utilizzare lo strumento sbagliato per un lavoro che deve ancora essere fatto. Quindi inizia con questo:

What's the problem I'm trying to solve?

Dalla descrizione, è necessario verificare che tutti gli script di database siano conformi ad alcuni standard.

What tools/processes are available to solve the problem?

La qualità del codice sorgente viene solitamente controllata dagli strumenti analisi statica . Se non si dispone di uno strumento di analisi statico per convalidare l'SQL, è possibile creare uno strumento rapido e sporco che esegua il controllo su qualsiasi file SQL passato ad esso. Non fa male controllare se ci sono strumenti di analisi statica in grado di gestire i problemi di cui parli.

Se crei quella parte della tua infrastruttura di build, come incorporarla in Jenkins o qualcosa del genere, può essere applicata a tutti i file SQL nel tuo progetto.

L'unit test risolve solo il problema per il tuo file corrente.

How do I communicate the need for the tool?

Questo è abbastanza facile, parli con il tuo team lead. Può collaborare con il proprietario del prodotto e con te per determinare il rischio / la ricompensa dell'investimento nell'attrezzatura. Se questo è probabilmente un problema una tantum, la strumentazione sarebbe probabilmente eccessiva. Se gli strumenti per catturare i maggiori problemi sono facili, potrebbe valerne la pena solo per il controllo di integrità.

Il tuo team lead potrebbe avere idee che tu (o io) non abbiamo considerato, in grado di risolvere il problema in modo più corretto.

    
risposta data 30.10.2017 - 20:10
fonte
19

È una cattiva pratica chiamare test che accedono ai file "Test unità".

He: "These things don't belong in unit tests"

You: "Makes sense, but I couldn't find a better place to put them. Where do they belong?"

Sfortunatamente, quali tipi di test esistono e come sono organizzati è del tutto specifico per la società. Quindi dovrai scoprire come la tua azienda gestisce questi test.

Se non hai ancora modo di eseguire test automatici diversi dai Test unitari, l'approccio pragmatico consiste nel contrassegnare i Test unitari che in realtà non sono Test unitari con un prefisso, finché non ne hai abbastanza per iniziare a capire che tipo di test hai effettivamente / bisogno. Successivamente puoi iniziare a organizzare.

    
risposta data 31.10.2017 - 00:56
fonte
14

Michael Feathers lo dice nel suo libro Working Effectively With Legacy Code:

In the industry, people often go back and forth about whether particular tests are unit tests. [...] I go back to the two qualities: Does the test run fast? Can it help us localize errors quickly?

Il test aiuterà a localizzare rapidamente gli errori ea correre velocemente? Se sì, allora fallo! Se no, allora non farlo! È così semplice!

Detto questo, stai lavorando in un ambiente con altre persone e devi andare d'accordo con loro. Potresti dover finire a farlo a modo suo, anche se in privato non sei d'accordo.

    
risposta data 31.10.2017 - 02:45
fonte
10

Ho scritto test simili, a volte, contro file di codice sorgente, file di configurazione e così via. Non li chiamerei unit-test perché (a) stanno accedendo al file system e potrebbero non essere ultra-veloci (b) Non mi interessa se vengono eseguiti ad ogni check-in (al contrario di notte su un Server CI).

Potresti chiamarli test di integrazione; certamente, sono più vicini a quella prospettiva dei test unitari.

Il mio termine personale per loro è test delle risorse . IMHO, sono del tutto giustificati se eseguiti di notte su un server CI: c'è un costo minimo e, se usato con giudizio, aggiunge chiaramente valore. Una definizione di giudiziosamente : se il test sta verificando un problema che ha causato un problema (ad esempio la codifica che hai menzionato).

    
risposta data 31.10.2017 - 01:11
fonte
4

Un test unitario consiste nel testare un metodo o "unità" di codice. Stai testando il più piccolo gruppo di logica e codice nel tuo software.

Successivamente, quando ti unisci a quello con altre unità, eseguirai test di integrazione.

Spero che il tuo team abbia incoraggiato la tua iniziativa e avrebbe dovuto offrire suggerimenti alternativi. Hai sicuramente l'idea giusta.

Il tuo SQL è codice proprio come qualsiasi linguaggio di bassa generazione come C # o Java e dovrebbe essere testato come tale. E la verifica e la convalida appartengono a tutti i livelli di test. Quindi le istruzioni di codifica e SET sono incluse, ma non necessariamente testate esclusivamente. Le cose generali come le terminazioni di riga o l'inclusione di solito possono semplicemente utilizzare un aggancio o una funzione SCM.

La best practice consiste nell'effettuare test di regressione per garantire che i bug del passato non vengano reintrodotti. Generalmente, i test vengono creati insieme a qualsiasi risoluzione del bug. Se questi bug non sono coperti da test di regressione su unità / integrazione o livello di sistema e poi reintrodotti è un problema di squadra, un problema di processo, non individuale.

Il fatto è che ... errori di sintassi, dichiarazioni mancanti o blocchi logici all'interno di una "unità" non vengono tipicamente testati. Stai testando gli ingressi e le uscite dell'unità in diverse combinazioni, testando le molte possibilità che potrebbero essere generate.

Tornare alle istruzioni SET mancanti - aiutano a informare le molte possibilità di input e output da testare. Quale test avresti scritto che sarebbe FAIL se ti mancava un SET scelto?

    
risposta data 31.10.2017 - 06:07
fonte
3

Se hai file che diventano parte del tuo prodotto, i loro contenuti devono essere corretti. Nessun motivo per cui non lo verificherai. Ad esempio se hai bisogno di sei 1024x 1024 immagini in qualche cartella, allora scrivi con tutti i mezzi un test unitario che verifica che tu abbia esattamente quello.

Ma probabilmente non hai solo i file, hai anche un codice che legge i file. Potresti scrivere un test unitario per quel codice. Nell'esempio sopra, la funzione di lettura di una delle sei immagini restituisce un'immagine 1024 x 1024 in memoria (o qualsiasi altra cosa che avrebbe dovuto produrre).

Ad ogni modo, potrebbe non essere un test unitario, ma è un test utile. E se usi un quadro di test unitario che ti permetta di fare un test utile (che non è un test unitario), perché non usare il quadro di test unitario?

    
risposta data 30.10.2017 - 21:00
fonte
2

Forse sto fraintendendo il tuo problema, ma per me questo sembra un problema che non dovrebbe essere catturato da alcun tipo di test dedicato ma semplicemente dal sistema di controllo della versione . Qualsiasi modifica a una base di codice dovrebbe essere rivista su base patch per patch prima di eseguire il commit. Un modo semplice per farlo in git è aggiungere le modifiche con

git add -p

In questo modo, per ogni modifica di un file di testo, la directory di lavoro ti chiederà se vuoi davvero mantenerla. Ciò consentirebbe di vedere, ad esempio, la cancellazione di quelle "dichiarazioni iniziali SET ".

Nel caso in cui la codifica di un intero file fosse cambiata, sarebbe comunque accaduto qualcosa di diverso: l'algoritmo non sarebbe riuscito a diffare il vecchio e il nuovo file, e quindi git add -p non aggiungerebbe nulla. Questo sarebbe quindi visibile nell'altro comando che farei prima di qualsiasi commit, ovvero

git status

Qui vedresti il file evidenziato in rosso, indicando che sono modifiche. Indagare perché questi non sono riusciti a raggiungere git add -p potrebbe rendere il problema ovvio.

    
risposta data 31.10.2017 - 20:58
fonte
1

Un altro angolo da considerare: poiché queste due condizioni sono requisiti per l'esecuzione del programma, non dovresti incorporare la logica vicino alla logica di esecuzione? Voglio dire: testate l'esistenza di un file prima di leggerlo e / o convalidarne il contenuto, giusto? quindi come è diverso? Penso che poiché si tratta di una risorsa esterna al codice, dovrebbe essere convalidata in fase di runtime, prima che venga effettivamente utilizzata. Risultato: applicazione più potente, non è necessario scrivere test aggiuntivi.

    
risposta data 31.10.2017 - 12:56
fonte
1

I test sono lo stesso codice di tutti gli altri e, se abbastanza complessi, beneficiano anche di ... test di unità. Sembra più semplice aggiungere tali controlli di precondizione direttamente nel test.

La maggior parte dei test è abbastanza semplice da non richiedere questo, ma se alcuni sono sufficientemente complessi, non vedo nulla di fondamentalmente sbagliato con questi controlli pre-condizionali. Naturalmente, il test dovrebbe anche fallire senza di loro, ma un buon test unitario dice anche a quale unità sta fallendo.

Uno script che viene utilizzato come parte del test e che deve avere determinati contenuti e codifiche è probabilmente un'unità. Potrebbe avere molto più codice e logica rispetto al resto del test. Un test con tale script non è il miglior progetto di sempre e, se possibile, dovrebbe essere rifatto in qualcosa di più diretto (a meno che non si tratti di test di integrazione).

    
risposta data 01.11.2017 - 20:57
fonte
1

Innanzitutto - uno degli scopi dei test è evitare che i problemi si ripetano nel tuo codice - quindi dovresti assolutamente continuare a scrivere test di questo tipo.

In secondo luogo - la denominazione è difficile. Sì, questi non sono chiaramente "test unitari", ma possono essere parti desiderabili e necessarie del processo di costruzione, perché ti proteggono da errori evidenti e perché ti danno un feedback sugli errori prima possibile (soprattutto se non vedi il conseguenze su una scatola di sviluppo).

Quindi, la domanda è (dovrebbe essere nel tuo contesto) più su quando e come questi test vengono eseguiti rispetto a quello che sono.

Ho usato questo tipo di test in passato - ci hanno risparmiato un bel po 'di dolore.

    
risposta data 02.11.2017 - 12:48
fonte
1

I test unitari riguardano l'esecuzione di un'unità di codice in isolamento per confermare che sta producendo il risultato corretto per l'input corretto. L'isolamento dovrebbe rendere sia l'unità sotto test che il test stesso ripetibile, cioè non dovrebbe dipendere o introdurre effetti collaterali.

SQL non è esattamente qualcosa che può essere testato separatamente, quindi qualsiasi test di SQL non è esattamente un test unitario e, ad eccezione delle istruzioni SELECT, ha quasi sicuramente un effetto collaterale. Possiamo chiamarlo un test di integrazione piuttosto che un test unitario.

È sempre opportuno assicurarsi che qualsiasi difetto che potrebbe essere introdotto possa essere rilevato il prima possibile nel ciclo di sviluppo e vantaggioso farlo in un modo che renda facile identificare la fonte del difetto in modo che può essere rapidamente corretto.

I test in questione possono essere trasferiti in modo più appropriato fuori dal corpo di "unit test" e collocati altrove, ma non dovrebbero essere rimossi del tutto se stanno facendo qualcosa di utile come evitare l'eventuale introduzione di un difetto che potrebbe richiedere ore per rintracciare.

    
risposta data 05.11.2017 - 19:32
fonte

Leggi altre domande sui tag