Bene ... sì , in realtà, se ogni percorso "attraverso" il programma viene testato. Ciò significa che ogni possibile percorso attraverso l'intero spazio di tutti i possibili stati che il programma può avere, comprese tutte le variabili. Anche per un programma compilato staticamente molto semplice - diciamo, un vecchio cruncher numerico Fortran - questo non è fattibile, anche se può almeno essere immaginabile: se hai solo due variabili intere, in pratica hai a che fare con tutti i modi possibili per collegare punti su una griglia bidimensionale; in realtà assomiglia molto al commesso viaggiatore. Per n tali variabili, hai a che fare con uno spazio n- dimensionale, quindi per qualsiasi programma reale, l'attività è completamente irrintracciabile.
Peggio: per cose serie, si ha non solo un numero fisso di variabili primitive, ma creare le variabili al volo in chiamate di funzione, o avere variabili di dimensione variabile ... o qualcosa di simile, per quanto possibile in un linguaggio Turing-completo. Ciò rende lo spazio dello stato infinito-dimensionale, mandando in frantumi tutte le speranze di piena copertura, anche con apparecchiature di test assurdamente potenti.
Detto questo ... in realtà le cose non sono così cupe. Si è possibile proove interi programmi siano corrette, ma dovrete rinunciare a un paio di idee.
Primo: è consigliabile passare a una lingua dichiarativa. I linguaggi imperativi, per qualche ragione, sono sempre stati i più popolari, ma il modo in cui mescolano algoritmi e interazioni del mondo reale rende estremamente difficile persino dire cosa intendi con "corretto".
Molto più facile nei linguaggi di programmazione puramente funzionali : questi hanno una chiara distinzione tra le proprietà veramente interessanti delle funzioni matematiche e le interazioni fuzzy del mondo reale di cui non si può davvero dire nulla. Per le funzioni, è molto facile specificare il "comportamento corretto": se per tutti i possibili input (dai tipi di argomento) viene visualizzato il risultato desiderato corrispondente, la funzione si comporta correttamente.
Ora, dici che è ancora intrattabile ... dopo tutto, lo spazio di tutti i possibili argomenti è in generale anche di dimensione infinita. È vero, anche se per una singola funzione, anche un test di copertura ingenuo ti porta molto più lontano di quanto tu possa mai sperare in un programma imperativo! Tuttavia, esiste un incredibile strumento potente che cambia il gioco: quantificazione universale / polimorfismo parametrico . Fondamentalmente, questo ti consente di scrivere funzioni su tipi di dati molto generali, con la garanzia che se funziona per un semplice esempio dei dati, funzionerà per qualsiasi possibile input.
Almeno teoricamente. Non è facile trovare i tipi giusti che sono davvero così generali che puoi provarlo completamente - di solito, hai bisogno di un linguaggio tipizzato in modo dipendente , e questi tendono ad essere piuttosto difficili da usare. Ma scrivere in uno stile funzionale con il solo polimorfismo parametrico aumenta già in modo enfatico il tuo "livello di sicurezza": non troverai necessariamente tutti i bug, ma dovrai nasconderli abbastanza bene in modo che il compilatore non li veda!