Domanda

Ho iniziato a esaminare l'intera idea di sviluppo unit test / test-driven, e più ci penso, più sembra ricoprire un ruolo simile al controllo statico del tipo. Entrambe le tecniche forniscono un controllo in fase di compilazione e una risposta rapida per determinati tipi di errori nel programma. Tuttavia, correggimi se sbaglio, ma sembra che una suite di test unitari con copertura completa testerebbe tutto ciò che verificherebbe il controllo del tipo statico, e poi alcuni. O in altri termini, i controlli di tipo statico vanno solo in parte a & Quot; prove & Quot; che il tuo programma sia corretto, mentre i test unitari ti permetteranno di " provare " quanto vuoi (in una certa misura).

Quindi, c'è qualche motivo per usare una lingua con controllo statico del tipo se stai usando anche il test unitario? È stata posta una domanda in qualche modo simile qui , ma vorrei approfondire . Quali sono i vantaggi specifici del controllo statico del tipo rispetto ai test unitari? Vengono in mente alcuni problemi come l'ottimizzazione del compilatore e l'intellisense, ma ci sono altre soluzioni per questi problemi? Ci sono altri vantaggi / svantaggi a cui non ho pensato?

È stato utile?

Soluzione

Penso che il testing di unità automatizzato sarà importante per linguaggi tipizzati dinamici, ma ciò non significa che sostituirà il controllo statico del tipo nel contesto in cui si applica. In effetti, alcuni di coloro che usano la digitazione dinamica potrebbero effettivamente usarla perché non vogliono i fastidi di controlli di sicurezza di tipo costante.

I vantaggi offerti dalle lingue tipizzate dinamicamente rispetto alle lingue tipizzate statiche vanno ben oltre i test e la sicurezza dei tipi è solo un aspetto. Anche gli stili di programmazione e le differenze di progettazione rispetto ai linguaggi tipizzati dinamici e statici variano notevolmente.

Inoltre, i test unitari scritti in modo troppo vigoroso per far rispettare la sicurezza dei tipi significherebbero che il software non dovrebbe essere digitato in modo dinamico dopo tutto, o che il progetto applicato dovrebbe essere scritto in un linguaggio tipicamente statico, non in uno dinamico.

Altri suggerimenti

C'è un fatto immutabile sulla qualità del software.

  

Se non può essere compilato, non può essere spedito

In questa regola, le lingue tipizzate staticamente vinceranno sulle lingue tipizzate dinamicamente.

Ok, sì, questa regola non è immutabile. Le app Web possono essere fornite senza compilazione (ho distribuito molte app Web di prova che non sono state compilate). Ma ciò che è fondamentalmente vero è

  

Prima si rileva un errore, più economico è riparare

Un linguaggio tipicamente statico eviterà che si verifichino errori reali in uno dei primi momenti possibili del ciclo di sviluppo del software. Un linguaggio dinamico no. Unit Testing, se sei approfondito a un livello super umano può prendere il posto di un linguaggio tipicamente statico.

Tuttavia, perché preoccuparsi? Ci sono un sacco di persone incredibilmente intelligenti là fuori che scrivono per te un intero sistema di controllo degli errori sotto forma di un compilatore. Se sei preoccupato di ricevere errori prima usa una lingua tipizzata staticamente.

Per favore, non prendere questo post come un imbroglio di linguaggi dinamici. Uso quotidianamente linguaggi dinamici e li adoro. Sono incredibilmente espressivi e flessibili e consentono programmi incredibilmente fan. Tuttavia, in caso di segnalazione precoce di errori, perdono in linguaggi tipizzati staticamente.

Per qualsiasi progetto di dimensioni ragionevoli, non è possibile tenere conto di tutte le situazioni con solo test unitari.

Quindi la mia risposta è " no " e anche se riesci a tenere conto di tutte le situazioni, hai quindi sconfitto l'intero scopo di usare un linguaggio dinamico in primo luogo.

Se vuoi programmare un tipo sicuro, usa meglio un linguaggio sicuro.

Avere una copertura del codice del 100% non significa che hai testato completamente la tua applicazione. Considera il seguente codice:

if (qty > 3)
{
    applyShippingDiscount();
}
else
{
    chargeFullAmountForShipping();
}

Posso ottenere una copertura del codice del 100% se inserisco i valori di qty = 1 e qty = 4.

Ora immagina che la mia condizione commerciale fosse che " ... per ordini di 3 o più articoli devo applicare uno sconto sui costi di spedizione .. " ;. Quindi avrei bisogno di scrivere test che funzionassero sui confini. Quindi progetterei test in cui la quantità era di 2,3 e 4. Ho ancora una copertura del 100%, ma soprattutto ho trovato un bug nella mia logica.

E questo è il problema che ho concentrandomi solo sulla copertura del codice. Penso che nella migliore delle ipotesi si finisca con una situazione in cui lo sviluppatore crea alcuni test iniziali basati sulle regole aziendali. Quindi, al fine di aumentare il numero di copertura, fanno riferimento al loro codice durante la progettazione di nuovi casi di test.

La tipizzazione manifesta (che suppongo tu intenda) è una forma di specifica, il test unitario è molto più debole poiché fornisce solo esempi. La differenza importante è che una specifica dichiara ciò che deve contenere in ogni caso, mentre un test copre solo esempi. Non puoi mai essere sicuro che i tuoi test coprano tutte le condizioni al contorno.

Le persone tendono anche a dimenticare il valore dei tipi dichiarati come documentazione. Ad esempio se un metodo Java restituisce un List<String>, allora so immediatamente cosa ottengo, non ho bisogno di leggere documentazione, casi di test o persino il codice del metodo stesso. Allo stesso modo per i parametri: se il tipo viene dichiarato, so cosa si aspetta il metodo.

Il valore di dichiarare il tipo di variabili locali è molto più basso poiché nel codice ben scritto l'ambito dell'esistenza della variabile dovrebbe essere piccolo. Puoi comunque usare la tipizzazione statica: invece di dichiarare il tipo lasci che il compilatore lo deduca. Lingue come Scala o persino C # ti permette di fare proprio questo.

Alcuni stili di test si avvicinano a una specifica, ad es. QuickCheck o è la variante Scala ScalaCheck genera test basati su specifiche, cercando di indovinare i limiti importanti.

Direi diversamente: se non hai un linguaggio tipicamente statico, meglio fare test unitari molto approfonditi se hai intenzione di fare qualcosa " & vera quot; con quel codice.

Detto questo, la tipizzazione statica (o meglio, la tipizzazione esplicita) ha alcuni vantaggi significativi rispetto ai test unitari che mi fanno preferire in generale. Crea API molto più comprensibili e consente una rapida visualizzazione del & Quot; skeleton & Quot; di un'applicazione (vale a dire i punti di ingresso a ciascun modulo o sezione di codice) in un modo molto più difficile con un linguaggio tipizzato dinamicamente.

Per riassumere: a mio avviso, dati test unitari solidi e approfonditi, la scelta tra una lingua tipizzata in modo dinamico e una lingua tipicamente statica è per lo più di gusto. Alcune persone preferiscono uno; altri preferiscono l'altro. Usa lo strumento giusto per il lavoro. Ma ciò non significa che siano identici: i linguaggi tipizzati staticamente avranno sempre un vantaggio in certi modi e i linguaggi tipizzati dinamicamente avranno sempre un vantaggio in certi modi diversi. I test unitari fanno molto per minimizzare gli svantaggi delle lingue tipizzate in modo dinamico, ma non le eliminano completamente.

No.

Ma questa non è la domanda più importante, la domanda più importante è: importa che non ci riesca?

Considera lo scopo del controllo del tipo statico: evitare una classe di difetti del codice (bug). Tuttavia, questo deve essere valutato nel contesto del dominio più ampio di tutti i difetti di codice. Ciò che conta di più non è un confronto lungo uno stretto frammento ma un confronto tra la profondità e l'ampiezza della qualità del codice, la facilità di scrittura del codice corretto, ecc. Se riesci a trovare uno stile / processo di sviluppo che consenta al tuo team di produrre una qualità superiore codice più efficiente senza controllo statico del tipo, quindi ne vale la pena. Ciò è vero anche nel caso in cui siano presenti buchi nei test che verrebbero rilevati dal controllo del tipo statico.

Suppongo che potrebbe essere molto accurato. Ma perché preoccuparsi? Se la lingua sta già verificando per assicurarsi che i tipi statici siano corretti, non avrebbe senso testarli (dal momento che li ottieni gratuitamente).

Inoltre, se si utilizzano linguaggi tipizzati statici con un IDE, l'IDE può fornire errori e avvisi, anche prima della compilazione per il test. Non sono sicuro che ci siano applicazioni di test di unità automatizzate che possono fare lo stesso.

Considerati tutti i vantaggi di linguaggi dinamici e in ritardo di associazione, suppongo che sia uno dei valori offerti dai test unitari. Dovrai comunque codificare attentamente e intenzionalmente, ma questo è il requisito numero 1 per qualsiasi tipo di codice IMHO. Essere in grado di scrivere test chiari e semplici aiuta a dimostrare la chiarezza e la semplicità del tuo progetto e della tua implementazione. Fornisce inoltre indizi utili per coloro che vedranno il tuo codice in un secondo momento. Ma non credo che conterei su di esso per rilevare tipi non corrispondenti. Ma in pratica non trovo che il controllo del tipo rilevi comunque molti errori reali. Non è solo un tipo di errore che riscontro nel codice reale, se in primo luogo hai uno stile di codifica chiaro e semplice.

Per javascript, mi aspetto che jsLint troverà quasi tutti i problemi di controllo del tipo. principalmente suggerendo stili di codifica alternativi per ridurre l'esposizione.

Il controllo del tipo aiuta a far rispettare i contratti tra componenti di un sistema. Il test unitario (come suggerisce il nome) verifica la logica interna dei componenti.

Per una singola unità di codice, penso che i test di unità possano davvero rendere superflua la verifica del tipo statico. Ma in un sistema complesso, i test automatizzati non possono verificare tutti i modi in cui i diversi componenti del sistema potrebbero interagire. Per questo, l'uso di interfacce (che sono, in un certo senso, una sorta di & Quot; contratto & Quot; tra i componenti) diventa uno strumento utile per ridurre potenziali errori. E le interfacce richiedono il controllo del tipo in fase di compilazione.

Mi piace molto programmare in linguaggi dinamici, quindi di certo non mi baso sulla digitazione dinamica. Questo è solo un problema che mi è capitato di recente. Sfortunatamente non ho alcuna esperienza nell'uso di un linguaggio dinamico per un sistema ampio e complesso, quindi sarei interessato a sentire da altre persone se questo problema è reale o semplicemente teorico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top