I test verificano che le cose che possono andare male non non vadano storte. Più flessibile è un sistema software, più modi ci sono per cui le cose vanno male. Al contrario, rimuovere la flessibilità da un sistema significa che meno cose possono andare storte, e di conseguenza è necessario testare meno cose per ottenere un livello di confidenza simile .
Ad esempio, sistemi di tipo statico. Un sistema di tipi è una prova automatica di correttezza. Il livello di comprovata correttezza dipende dalla lingua, ad es. Haskell può dimostrare più proprietà di Java, che spesso può dimostrare più proprietà di C. Le proprietà del programma che sono garantite da un sistema di tipi non devono essere testate da unità, per esempio che una funzione restituisce un risultato di un tipo particolare .
L'immutabilità è un altro approccio che diminuisce la flessibilità di un sistema, ma rende anche più facile ragionare e quindi richiede meno test. In particolare, lo stato di un oggetto mutabile può cambiare dopo la sua costruzione. Queste modifiche di stato possono spostare quell'oggetto in uno stato non valido. Quindi un test approfondito dovrà verificare queste transizioni di stato e assicurare che non possano essere raggiunti stati illegali. I consumatori di questo oggetto dovranno essere testati per poter lavorare con l'oggetto in uno qualsiasi dei suoi stati. Al contrario, lo stato di un oggetto immutabile non può cambiare una volta costruito. Pertanto, non ci sono transizioni di stato da testare. Se un consumatore riceve un'istanza, sa sempre che si trova nel singolo stato valido per quella classe.
Quando testiamo una funzione, vogliamo affermare che ha qualche effetto desiderato. Quindi organizzare uno stato particolare, agire fuori dal caso di test richiamando la funzione, e asserire che lo stato dopo la chiamata ha alcune proprietà previste . Questo è più facile quando la funzione non ha alcun effetto tranne che per restituire un valore: quando abbiamo una funzione pura . L'immutabilità non è una precondizione per una pura funzione. Ma se quella funzione passa parametri immutabili, sappiamo che la funzione non può cambiare quei parametri - una cosa in meno che potrebbe andare storta. Nota che per un metodo, il parametro implicito this
è anche un parametro di input che può essere modificato o meno.
In pratica, l'immutabilità non è sempre possibile e non sempre auspicabile. In particolare, l'ecosistema Java non ha un meccanismo per tracciare se i valori sono immutabili e se un parametro può essere modificato (confrontare const
in C ++). Quindi, in Java, l'immutabilità e le funzioni pure sono più una convenzione che una proprietà di correttezza dimostrabile del tipo di sistema. Inoltre, alcune funzioni possono essere effettivamente pure ma non pure nel senso più letterale, ad es. se eseguono la registrazione come un effetto collaterale. Ma questo è del tutto OK, poiché tali funzioni sono ancora effettivamente pure da una prospettiva di un chiamante.
Nella mia esperienza, preferendo i disegni immutabili e mescolando OOP con tecniche di programmazione funzionale, è più semplice, sistemi più ragionevoli . Che abbiamo bisogno di meno test per tali sistemi non è il valore principale, ma solo una conseguenza di un sistema generalmente più semplice in cui meno cose possono andare storte.