In che modo verrebbero rilevati errori di tipo durante la creazione di mock in un linguaggio dinamico?

10

Il problema si verifica mentre si esegue TDD. Dopo un paio di passaggi di test, i tipi di ritorno di alcune classi / moduli cambiano. In un linguaggio di programmazione tipizzato in modo statico, se nei test di alcune classi altro è stato utilizzato un oggetto simulato precedente e non è stato modificato per riflettere la modifica del tipo, si verificheranno errori di compilazione.

Tuttavia, per le lingue dinamiche, la modifica dei tipi di ritorno potrebbe non essere rilevata e i test della classe altra continueranno a essere trasmessi. Certo potrebbero esserci dei test di integrazione che dovrebbero fallire in seguito, ma i test unitari passerebbero erroneamente. C'è un modo per evitarlo?

Aggiornamento con un campione banale (in alcune lingue inventate) ...

Versione 1:

Calc = {
    doMultiply(x, y) {return x * y}
}
//.... more code ....

// On some faraway remote code on a different file
Rect = {
    computeArea(l, w) {return Calc.doMultipy(x*y)}
}

// test for Rect
testComputeArea() { 
    Calc = new Mock()
    Calc.expect(doMultiply, 2, 30) // where 2 is the arity
    assertEqual(30, computeArea)
}

Ora, nella versione 2:

// I change the return types. I also update the tests for Calc
Calc = {
    doMultiply(x, y) {return {result: (x * y), success:true}}
}

... Rect genererà quindi un'eccezione in runtime, ma il test continuerà comunque.

    
posta jvliwanag 02.01.2013 - 13:36
fonte

2 risposte

2

In una certa misura, questo è solo una parte del costo di fare affari con linguaggi dinamici. Ottieni molta flessibilità, altrimenti nota come "abbastanza corda per impiccarti". Stai attento con questo.

Per me, il problema suggerisce l'utilizzo di tecniche di refactoring differenti rispetto a quelle di un linguaggio tipizzato in modo statico. In un linguaggio statico, si sostituiscono i tipi restituiti in parte in modo da poter "appoggiarsi al compilatore" per trovare quali posizioni potrebbero rompersi. È sicuro farlo e probabilmente più sicuro che modificare il tipo di reso sul posto.

In un linguaggio dinamico, non puoi farlo, quindi è molto più sicuro modificare il tipo di reso in luogo, anziché sostituirlo. Forse lo modifichi aggiungendo la tua nuova classe ad esso come membro, per le classi che ne hanno bisogno.

    
risposta data 02.01.2013 - 14:16
fonte
2

Se il tuo codice cambia e i tuoi test continuano a passare, allora c'è qualcosa di sbagliato nei tuoi test (cioè ti manca un'affermazione), o il codice non ha in realtà modificato.

Che cosa intendo con questo? Bene, i tuoi test descrivono i contratti tra parti del tuo codice. Se il contratto è "il valore restituito deve essere iterabile", quindi la modifica del valore di ritorno da una matrice ad una lista è non in realtà una modifica del contratto e pertanto non provocherà necessariamente un errore di test .

Per evitare asserzioni mancanti, puoi usare strumenti come l'analisi della copertura del codice (non ti dirà quali parti del tuo codice sono testate, ma ti ti dirà quali parti sono decisamente < non sono testati), complessità ciclomatica e complessità NPath (che ti danno un limite inferiore al numero di asserzioni richieste per raggiungere la copertura completa del codice C1 e C2) e tester di mutazione (che iniettano mutazioni nel tuo codice come trasformare true in false , i numeri negativi in positivo, gli oggetti in null ecc. e controllare se questo fa fallire i test).

    
risposta data 02.01.2013 - 17:10
fonte

Leggi altre domande sui tag