Devo scrivere test quando posso dimostrare la correttezza del codice?

8

La gente dice che "parlare di TDD funziona a malapena, se vuoi convincere qualcuno a TDD, mostra loro i risultati". Tuttavia, sto già ottenendo ottimi risultati senza TDD. Mostrandomi che le persone che usano TDD ottengono buoni risultati non saranno convincenti, voglio vedere che le persone che scrivono sia TDD che non-TDD ottengono risultati migliori con TDD.

Nonostante tutto ciò, sono interessato a dare una prova a TDD. Comunque non sono convinto che guadagnerò qualcosa da questo. Se si rivelerà utile, cercherò di spingerlo al resto della mia squadra.

La mia domanda principale è questa: TDD servirebbe a qualsiasi scopo per il codice, se posso già dimostrare la correttezza del codice?

Ovviamente, nessuno dei due è un proiettile d'argento. La tua prova potrebbe essere sbagliata perché ti sei perso un dettaglio e il tuo test potrebbe non riuscire a individuare un bug per cui non sei riuscito a testare. Alla fine, siamo umani, nessuno può fare il codice senza errori al 100% per sempre. Possiamo solo cercare di avvicinarci il più possibile.

Tuttavia, TDD potrebbe effettivamente salvare in qualsiasi momento del codice che ha dimostrato la sua correttezza? cioè codice che, nella macchina a stati in cui opera il codice, tutti gli stati possibili validi ei relativi intervalli sono riconosciuti dallo sviluppatore, tutti sono contabilizzati e il codice è progettato in un controllo degli errori in stile whitelist che passa ogni eccezione a un gestore superiore per assicurarsi che non vi siano perdite impreviste - > senza che entrambi visualizzino un messaggio pertinente (entro) sul client e invii notifiche di registro a un amministratore.

Le risposte con esempi di vita reale sarebbero migliori.

Alcuni chiarimenti:

  • Questa domanda non riguarda la possibilità di provare la correttezza del codice o meno. Assumiamo per impostazione predefinita che non tutto il codice può essere dimostrato corretto entro un ragionevole lasso di tempo, ma che alcuni pezzi di codice possono essere. Ad esempio, è molto facile dimostrare la correttezza di un modulo FizzBuzz. Non molto facile per un servizio di sincronizzazione dei dati basato su cloud.

  • All'interno di questo confine, la domanda chiede quanto segue: Inizia con il presupposto che un codebase è diviso in 2 parti: [I] parti che sono state dimostrate corrette [II] parti che non sono state dimostrate corrette, ma testate manualmente per funzionare.

  • Voglio applicare le pratiche TDD a questo codebase che non le possedeva fino ad ora. La domanda richiede quanto segue: il TDD dovrebbe essere applicato a ogni singolo modulo, o sarebbe sufficiente applicarli solo ai moduli che non sono stati dimostrati corretti?

  • "Proven correct" significa che puoi considerare questo modulo completamente funzionale, vale a dire, non fa affidamento su nessuno stato globale o esterno al di fuori di se stesso, e ha interamente la propria API per I / O che altri moduli che interagire con esso deve seguire. Non è possibile "rompere questo modulo" cambiando il codice al di fuori del modulo, nel peggiore dei casi si può abusarne e ricevere messaggi di errore formattati.

  • Ovviamente, ogni regola ha delle eccezioni, i bug del compilatore nelle nuove versioni del compilatore potrebbero introdurre dei bug in questo modulo, ma gli stessi bug potrebbero essere introdotti ai test che lo hanno testato e hanno dato un falso senso di sicurezza ai test che non più lavoro come previsto. La linea di fondo è che i test non sono una soluzione magica, sono un altro livello di protezione, e questa domanda discute la questione se questo strato di protezione valga lo sforzo nel caso specifico di un modulo che è stato dimostrato corretto (supponiamo che era davvero).

posta Kylee 02.04.2018 - 19:54
fonte

7 risposte

20

Sì.

Le dimostrazioni vanno bene quando sono disponibili, ma anche nel migliore dei casi dimostrano solo che un singolo bit di codice funzionerà come previsto (per tutti gli input? tenendo conto delle interruzioni nel mezzo di qualsiasi operazione? esaurimento della memoria? errore del disco? errore di rete?).

Che cosa accade quando cambia?

I test sono grandi perché servono come un contratto implicito su ciò che il codice dovrebbe fare. Forniscono alcune impalcature in modo che il tuo nuovo tirocinante possa entrare e apportare modifiche con un certo livello di sicurezza. Tutto tramite risultati rapidi e chiari: passa o fallisci.

E, francamente, posso istruire uno stagista a scrivere test di unità fattibili in pochi mesi. Dubito che chiunque nel mio team (me compreso) possa creare prove che garantiscano qualcosa di significativo per il codice non banale; per non parlare di farlo in modo rapido e preciso.

    
risposta data 02.04.2018 - 22:07
fonte
5

Non lo sappiamo. Non possiamo rispondere alla tua domanda.

Mentre passi un sacco di tempo a spiegare quel processo che ora sembra funzionare per la soddisfazione di tutti, ci stai dicendo solo un piccolo frammento di ciò che sta realmente accadendo.

Dalla mia esperienza, ciò che stai descrivendo è estrema rarità e sono scettico sul fatto che sia in realtà il tuo processo e approccio alla codifica che è in realtà causa di basso numero di errori nelle tue applicazioni. Potrebbero esserci molti altri fattori che influenzano le tue applicazioni e non ci stai dicendo nulla su questi fattori.

Quindi non sappiamo, di fronte a non conoscere il tuo ambiente di sviluppo e cultura esatti, se TDD ti aiuterà o no. E possiamo passare giornate a discutere e discutere su questo.

C'è solo una raccomandazione che possiamo darti: provalo. Sperimentare. Imparalo. So che stai cercando di dedicare meno sforzi per decidere, ma non è possibile. Se vuoi davvero sapere se TDD funzionerà nel tuo contesto, l'unico modo per scoprirlo è di fare effettivamente TDD. Se effettivamente lo impari e lo applichi alla tua applicazione, puoi confrontarlo con il tuo processo non TDD. Potrebbe essere che TDD abbia effettivamente dei vantaggi e tu decida di tenerlo. Oppure può venire fuori che TDD non porta nulla di nuovo e ti rallenta solo. In tal caso, puoi ricorrere al processo precedente.

    
risposta data 02.04.2018 - 22:02
fonte
5

Lo scopo principale dei test (unità) è salvaguardare il codice, assicurandosi che non si interrompa inosservato a causa di modifiche successive. Quando il codice viene scritto per la prima volta, riceverà molta attenzione e sarà esaminato attentamente. E potresti avere un sistema superiore per questo.

Sei mesi dopo, quando qualcun altro sta lavorando su qualcosa apparentemente non correlato, potrebbe rompersi e il vostro super-duplicatore di errori di correzione del codice non lo noterà. Sarà un test automatico.

    
risposta data 02.04.2018 - 22:07
fonte
5

I want to apply TDD practices to this codebase that did not have them until now.

Questo è il modo più difficile per imparare TDD. Più tardi esegui il test, più costa scrivere test e meno ne escono.

Non sto dicendo che sia impossibile adattare i test a una base di codice esistente. Sto dicendo che farlo non è in grado di far credere a nessuno un credente del TDD. Questo è un duro lavoro.

In realtà è meglio praticare il TDD la prima volta su qualcosa di nuovo ea casa. In questo modo impari il vero ritmo. Fai questo e lo troverai avvincente.

The question asks the following: should TDD be applied to every single module,

Questo è il pensiero strutturale. Non dovresti dire cose come testare ogni funzione, classe o modulo. Questi limiti non sono importanti per i test e dovrebbero essere comunque in grado di cambiare. TDD tratta di stabilire un bisogno comportamentale testabile e di non preoccuparsi di come è soddisfatto. Se non fosse non potremmo refactoring.

or would it be enough to apply them to only modules that were not proven correct?

È sufficiente applicarli dove ne trovi la necessità. Vorrei iniziare con un nuovo codice. Otterrai molto di più dai test prima che da tardi. Non farlo al lavoro finché non ti sei esercitato abbastanza per padroneggiarlo a casa.

Quando hai dimostrato che TDD è efficace con il nuovo codice al lavoro e ti senti abbastanza sicuro da accettare il vecchio codice, inizierei con il codice provato. Il motivo è perché sarai in grado di vedere subito se i test che stai scrivendo stanno prendendo il codice in una buona direzione.

My main question is this: Would TDD serve any purpose for code, if I can already prove the code correctness?

I test non dimostrano solo la correttezza. Mostrano l'intento. Mostrano ciò che è necessario. Indicano un percorso per cambiare. Un buon test dice che ci sono diversi modi per scrivere questo codice e ottenere quello che vuoi. Aiutano i nuovi programmatori a vedere cosa possono fare senza rompere tutto.

Solo una volta che hai giù dovresti vagare nel codice non provato.

Un avvertimento contro gli zeloti: sembra che tu abbia raggiunto il successo e quindi sarà improbabile che salti a capofitto. Ma altri che cercano di mettersi alla prova non saranno così riservati. TDD può essere esagerato. È incredibilmente facile creare una serie di test che in realtà danneggia il refactoring perché bloccano trival e roba priva di significato. Come succede? Perché le persone che cercano di mettere in mostra i test devono solo scrivere test e mai refactoring. Soluzione? Fà loro il refactoring. Fai in modo che si occupino delle modifiche alle funzionalità. Prima è meglio è. Questo ti mostrerà rapidamente i test inutili. Dimostri flessibilità flettendo.

Un avvertimento contro categorizzazione strutturale: alcune persone insisteranno sul fatto che una classe è un'unità. Alcuni chiameranno qualsiasi test con due classi un test di integrazione. Alcuni insistono sul fatto che non puoi attraversare il confine x e chiamarlo test unitario. Piuttosto che preoccuparti di ciò, ti consiglio di preoccuparti di come si comporta il tuo test. Può funzionare in una frazione di secondo? Può essere eseguito in parallelo con altri test (senza effetti collaterali)? Può essere eseguito senza avviare o modificare altre cose per soddisfare dipendenze e precondizioni? Metto queste considerazioni in anticipo se si parla di un DB, di un file system o di una rete. Perché? Perché questi ultimi tre sono solo problemi perché causano gli altri problemi. Raggruppa i test insieme in base a come puoi aspettarti che si comportino. Non sono i confini che incrociano. Allora sai cosa puoi aspettarti da ogni suite di test.

I've seen people say they don't want to use TDD because it would have too much overhead, and TDD supporters defend it by saying that once you get used to write TDD all the time there isn't much overhead.

Questa domanda ha già risposte qui .

    
risposta data 03.04.2018 - 02:35
fonte
1

Test Driven Development è più sulla prototipazione e sul brainstorming di un'API che sul testing. I test creati sono spesso di scarsa qualità e alla fine devono essere buttati fuori. Il vantaggio principale di TDD è determinare come verrà utilizzata un'API, prima di scrivere l'implementazione dell'API. Questo vantaggio può anche essere ottenuto in altri modi, ad esempio scrivendo la documentazione dell'API prima dell'implementazione.

Le prove di correttezza sono sempre più preziose dei test. I test non dimostrano nulla. Tuttavia, al fine di utilizzare le prove di correttezza in modo produttivo, è utile disporre di un correttore di prove automatizzate e sarà necessario lavorare con contratti di qualche tipo (progettazione per contratto o progetto basato su contratto).

In passato, quando lavoravo su sezioni critiche del codice, provavo le prove di correttezza manuale. Anche le prove informali sono più preziose di qualsiasi test automatizzato. Ma hai ancora bisogno dei test, a meno che tu non sia in grado di automatizzare le prove, perché in futuro le persone infrangeranno il tuo codice.

I test automatici non implicano TDD.

    
risposta data 02.04.2018 - 20:17
fonte
0

A) Stai leggendo il codice e ti stai convincendo che è corretto non lontanamente vicino a dimostrare che è corretto. Altrimenti perché scrivere test?

B) Quando modifichi il codice in cui vuoi eseguire test che dimostrano che il codice è ancora corretto o meno.

    
risposta data 21.04.2018 - 20:50
fonte
-1

Ti avverto dicendo che una volta che sei abituato a usare TDD in modo efficace, ti farà risparmiare tempo nel gioco finale. Ci vuole pratica per imparare a usare TDD in modo efficace, e non aiuta quando si è in difficoltà. Quando imparo come utilizzarlo al meglio, ti consiglio di iniziare da un progetto personale in cui hai più margine di manovra e meno pressione sugli orari.

Scoprirai che il tuo avanzamento iniziale è più lento mentre stai sperimentando di più e hai scritto la tua API. Nel corso del tempo, i tuoi progressi saranno più rapidi man mano che i nuovi test inizieranno a passare senza modificare il codice e avrai una base molto stabile da cui partire. Nel tardo gioco, il codice che non è stato creato usando TDD richiede di dedicare molto tempo al debugger mentre si cerca di capire cosa sta andando male di quanto dovrebbe essere necessario. Corri anche un rischio maggiore di rompere qualcosa che prima funzionava con nuove modifiche. Valuta l'efficacia di TDD rispetto a non utilizzarla per il tempo totale necessario al completamento.

Detto questo, TDD non è l'unico gioco in città. Puoi utilizzare BDD che utilizza un modo standard di esprimere il comportamento di un'applicazione a pila intera e valutare la correttezza dell'API da lì.

Tutta la tua argomentazione dipende da "proving code correctness", quindi hai bisogno di qualcosa che definisca la correttezza del codice. Se non si utilizza uno strumento automatico per definire cosa significa "corretto", la definizione è molto soggettiva. Se la tua definizione di corretto è basata sul consenso dei tuoi colleghi, ciò può cambiare in un dato giorno. La tua definizione di corretto deve essere concreta e verificabile, il che significa anche che dovrebbe essere in grado di essere valutata da uno strumento. Perché non usarne uno?

La # 1 conquista dall'utilizzo di test automatici di qualsiasi tipo, è che puoi verificare che il codice rimanga corretto anche quando le patch del sistema operativo vengono applicate in modo rapido ed efficiente. Esegui la tua suite per assicurarti che tutto stia passando, quindi applica la patch ed esegui di nuovo la suite. Ancora meglio, rendilo parte della tua infrastruttura di build automatizzata. Ora puoi verificare che il codice rimanga corretto dopo la fusione del codice da più sviluppatori.

La mia esperienza con TDD mi ha portato alle seguenti conclusioni:

  • È fantastico per il nuovo codice, difficile per la modifica dei sistemi legacy
  • Devi ancora sapere cosa stai cercando di realizzare (cioè avere un piano)
  • Rallenta per iniziare, ma fa risparmiare tempo più tardi
  • Ti costringe a pensare a come convalidare la correttezza e il debug da una prospettiva utente

La mia esperienza con BDD mi ha portato alle seguenti conclusioni:

  • Funziona sia per il vecchio sia per il nuovo codice
  • Convalida l'intero stack e definisce le specifiche
  • Più lento per essere attivo e in esecuzione (aiuta ad avere qualcuno che conosce il set di strumenti)
  • È necessario definire un numero minore di comportamenti rispetto ai test unitari

Definizione di corretto: il tuo codice è conforme ai requisiti. Ciò è meglio verificato con BDD, che fornisce un mezzo per esprimere tali requisiti in modo leggibile e verificarli in fase di esecuzione.

Non sto parlando della correttezza in termini di prove matematiche, che non è possibile. E sono stanco di avere questa discussione.

    
risposta data 02.04.2018 - 21:09
fonte

Leggi altre domande sui tag