Un'alternativa al richiedere il rosso in TDD: il ripristino del codice è in corso?

5

Secondo questa risposta a questa domanda , una buona ragione per iniziare sempre con un test non riuscito ("Rosso") è assicurarsi che il test sia lavorando e che il codice che verrà scritto è ciò che fa passare il test. (mia parafrasi)

Dal momento che mi sembra che la capacità di scrivere un test prima che un codice sia stato scritto è una sorta di acume mentale che non tutti possono fare (non posso), sarebbe sufficiente se scrivo prima il codice, quindi scrivi il test, quindi ripristina la modifica del codice per vedere che il test fallirà senza la modifica del codice?

Supponiamo che possa essere automatizzato con una sorta di integrazione IDE - sarebbe una forma alternativa di TDD?

Negli ambienti di sviluppo in cui TDD è applicato da IDE / Framework, l'applicazione rigorosa delle regole meccaniche limita le opzioni dello sviluppatore per le ottimizzazioni?

Un esempio in cui potrebbe essere utile:

Supponiamo che il modulo e i suoi test di unità siano già stati completati e che funzionino entrambi correttamente. Ora, voglio introdurre un refactoring che migliorerebbe le prestazioni di una quantità sconosciuta riducendo il numero di chiamate di funzione interne , senza alcun cambiamento fondamentale nella esterna comportamento del modulo.

Perché non so quanti benefici otterrei da quel refactoring, non posso scrivere un test per questo. Ma senza un test fallimentare, non sono autorizzato a modificare il codice. Questo sembra un problema di pollo e uova.

Se sono autorizzato a scrivere un test fittizio che cattura semplicemente il numero di chiamate di funzioni interne nel vecchio / nuovo codice e quindi modifica il codice (nel nome di "refactoring"), ora posso aggiornare il mio test ( se il refactoring ha successo nel ridurre il numero di chiamate interne) per affermare che il numero di chiamate interne dovrebbe essere ridotto.

(Ripensamento)

Anche se, questo tipo di test delle prestazioni ha un'importanza minore rispetto ai test unitari richiesti:

  • Vorrei mantenere il beneficio del codice più efficiente se non ci sono cambiamenti nei requisiti funzionali, e non voglio che gli altri "rifattorino" questo vantaggio basandosi sull'ipotesi che nessun requisito funzionale possa essere rotto.
  • Tuttavia, se si verifica una modifica dei requisiti funzionali e se non è possibile soddisfare il livello di prestazioni corrente, è necessario soddisfare prima i requisiti funzionali. Dopodiché, un nuovo obiettivo di rendimento verrà impostato dalla sperimentazione.

(Disclaimer: non ho mai fatto rigoroso TDD (e sono scettico su di esso), anche se ho fatto test-presto-dopo-coding per diversi mesi.)

Altre riflessioni

  • La modifica del codice in questa domanda sembra essere "sviluppo post-TDD", poiché si verifica bene dopo che tutti i requisiti funzionali sono stati soddisfatti e tutti i test sono stati effettuati. Pertanto, purché tutti i test dell'unità TDD originale continuino a passare, questo tipo di modifica del codice è considerato "tuning".
posta rwong 08.05.2011 - 17:33
fonte

5 risposte

3

Se la domanda è "Posso fare TDD senza prima scrivere il test", la risposta è no. Anche se si scrive codice, si prova e si ripristina, non si sta imparando come utilizzare TDD o si ottengono i vantaggi di guidare lo sviluppo con i test. Suggerisco di prendere il tempo per acquisire l'abilità di scrivere il test prima. Ne varrà la pena.

Puoi puoi scrivere prima il codice, non lo farai semplicemente TDD.

Nel tuo esempio, se hai test che coprono il comportamento , puoi refactoring. TDD parla di comportamento, non di implementazione (è per questo che preferisco BDD). Cambiare le prestazioni non sta cambiando il comportamento, sta cambiando l'implementazione. Questo è esattamente il tipo di cosa che facilita il test appropriato.

Per quanto riguarda il tuo ripensamento: i commenti sono appropriati quando il codice stesso non è e non può essere fatto per comunicare un intento. In questo esempio, il codice è stato scritto per le prestazioni e potrebbe essere importante consentire ai futuri sviluppatori di sapere che un determinato algoritmo ha determinati requisiti di complessità.

    
risposta data 08.05.2011 - 19:03
fonte
7

Un paio di cose che stai dicendo qui non corrispondono alla pratica o alla semantica dello standard XP.

without a failing test, I'm not allowed to modify the code.

Non così. Senza un test fallito, non ti è permesso aggiungere funzionalità. Refactoring include specificamente nella sua definizione (come lo usiamo in XP) non aggiungendo funzionalità; puoi refactoring senza aggiungere test.

I want to introduce a refactoring which would improve the performance by an unknown amount by reducing the number of internal function calls, without any fundamental change in the external behavior of the module.

Se hai eseguito TDD, il comportamento esterno del tuo sistema è già ben testato. Puoi andare avanti e cambiare le cose fintanto che mantieni il passaggio dei test. In genere, non ci aspettiamo di vedere miglioramenti significativi delle prestazioni da un puramente refactoring, ma faremo refactoring in modo tale da facilitare l'ottimizzazione delle prestazioni. Tali ottimizzazioni sono (di nuovo, tipicamente) non refactoring - cambiano il comportamento del sistema - e quindi, in un ambiente XP perfetto, saranno gli argomenti dei test, scritti per primi.

È possibile che un refactoring riorganizzativo come quello che descrivi possa influire sulle prestazioni; se pensi che lo farà (e soprattutto se lo fai nella speranza che lo farà), dovresti strumentare il codice e confrontare le prestazioni prima e dopo il refactoring.

Per quanto riguarda la tua domanda principale: penso che tu stia resistendo troppo duramente a TDD; Penso che trarrai beneficio dall'associazione con qualcuno che è a suo agio con la pratica e, in definitiva, penso che ti aiuterà a familiarizzare con la pratica in modo che tu possa scegliere di usarla o meno da una posizione meglio informata. Se ti rifiuti di TDD, la pratica che proponi potrebbe essere utile, ma non è TDD ed è improbabile che molti dei vantaggi di design di TDD vengano acquisiti con la tua pratica.

    
risposta data 08.05.2011 - 17:54
fonte
5

TDD riguarda la scrittura dell'API prima dell'implementazione. Scrivendo i test si progetta l'API da "Outside" invece di farlo come "hmm, come posso chiamare il codice che ho scritto". Devi farlo in questo modo per essere in grado di testare i risultati.

Non sono del tutto convinto che non sia assolutamente possibile scrivere semplici test che descrivono ciò che il codice che ti servirà. E il primo test fallirà perché non c'è alcun codice dietro di esso che fa ciò che ti aspetti. Aggiungendo la carne cambierai quello.

Riconsidera la tua situazione e prova a fare un altro tentativo.

    
risposta data 08.05.2011 - 19:55
fonte
1

Ciò che descrivi sembra un Test di caratterizzazione . Una buona ricetta per scrivere i test di caratterizzazione include i seguenti passaggi:

  • Usa un pezzo di codice in un'imbracatura di test
  • Scrivi un'affermazione che sai fallire
  • Lascia che l'errore ti dica quale sia il comportamento
  • Modifica il test in modo che si aspetti il comportamento che il codice produce
  • Ripeti

Tuttavia, questo non ha nulla a che fare con TDD, poiché il codice non è guidato dai test.

    
risposta data 08.05.2011 - 17:55
fonte
1

Dici di non avere "l'acume mentale" per scrivere prima i test. Penso che tu lo faccia. Se non puoi scrivere il test per primo, è segno che qualcos'altro è sbagliato.

Nel caso dell'esempio delle prestazioni, il problema è che stai testando qualcosa che non dovrebbe essere testato. Dovresti solo verificare che il tuo codice produca le risposte corrette non con la velocità con cui produce quelle risposte.

Il vantaggio principale di scrivere i test prima non è essere sicuri che il test fallisca prima che la modifica sia stata apportata. Piuttosto, il vantaggio è che ti costringe a pensare alla tua classe dal punto di vista dell'utente piuttosto che all'implementazione. In sostanza, ti costringe a progettare l'interfaccia prima.

Detto questo, a volte scrivo parti dell'implementazione. Un esempio potrebbe essere quando si scrive una funzione e non sono chiaro in anticipo quali input richiederanno la funzione. In tal caso scriverò una prima implementazione della funzione prima del test. Ma poi torno a testare prima per il resto dell'implementazione dell'unità.

    
risposta data 08.05.2011 - 21:44
fonte

Leggi altre domande sui tag