it-swarm.it

TDD funziona davvero per progetti complessi?

Sto ponendo questa domanda riguardo ai problemi che ho riscontrato durante i progetti TDD. Ho notato le seguenti sfide durante la creazione di unit test.

  • Generazione e gestione di dati fittizi

È difficile e non realistico mantenere grandi dati fittizi. È ancora più difficile quando la struttura del database subisce modifiche.

  • Test GUI

Anche con MVVM e la capacità di testare la GUI, ci vuole molto codice per riprodurre lo scenario della GUI.

  • Test del business

Ho esperienza che TDD funziona bene se lo si limita a una semplice logica aziendale. Tuttavia, la logica aziendale complessa è difficile da testare poiché il numero di combinazioni di test (spazio di test) è molto elevato.

  • Contraddizione nei requisiti

In realtà è difficile acquisire tutti i requisiti in fase di analisi e progettazione. Molte volte i requisiti di una nota portano alla contraddizione perché il progetto è complesso. La contraddizione si trova in ritardo nella fase di attuazione. TDD richiede che i requisiti siano corretti al 100%. In tali casi, ci si potrebbe aspettare che requisiti contrastanti vengano catturati durante la creazione di test. Ma il problema è che questo non è il caso in scenari complessi.

Ho letto questa domanda: Perché TDD funziona?

TDD funziona davvero per progetti aziendali complessi o è praticamente limitato al tipo di progetto?

53
Amir Rezaei

È difficile e non realistico mantenere grandi dati fittizi. È ancora più difficile quando la struttura del database subisce modifiche.

Falso.

Il test unitario non richiede dati fittizi "grandi". Richiede abbastanza dati fittizi per testare gli scenari e niente di più.

Inoltre, i programmatori veramente pigri chiedono agli esperti in materia di creare semplici fogli di calcolo dei vari casi di test. Solo un semplice foglio di calcolo.

Quindi il programmatore pigro scrive un semplice script per trasformare le righe del foglio di calcolo in casi di test unitari. È piuttosto semplice, davvero.

Quando il prodotto si evolve, i fogli di calcolo dei casi di test vengono aggiornati e vengono generati nuovi test unitari. Fallo sempre. Funziona veramente.

Anche con MVVM e la possibilità di testare la GUI, è necessario molto codice per riprodurre lo scenario della GUI.

Che cosa? "Riprodurre"?

Il punto di TDD è progettare cose per la testabilità (Test Drive Development). Se la GUI è così complessa, deve essere riprogettata per essere più semplice e più testabile. Più semplice significa anche più veloce, più gestibile e più flessibile. Ma per lo più più semplice significherà più testabile.

Ho esperienza che TDD funziona bene se lo si limita a una semplice logica aziendale. Tuttavia, la logica aziendale complessa è difficile da testare poiché il numero di combinazioni di test (spazio di test) è molto elevato.

Questo può essere vero.

Tuttavia, chiedere agli esperti in materia di fornire i casi di test di base in una forma semplice (come un foglio di calcolo) aiuta davvero.

I fogli di calcolo possono diventare piuttosto grandi. Ma va bene, dato che ho usato un semplice Python per trasformare i fogli di calcolo in casi di test.

E. Ho dovuto scrivere alcuni casi di test manualmente perché i fogli di calcolo erano incompleti.

Però. Quando gli utenti hanno segnalato "bug", ho semplicemente chiesto quale caso di test nel foglio di calcolo fosse errato.

In quel momento, gli esperti in materia avrebbero corretto il foglio di calcolo o avrebbero aggiunto esempi per spiegare cosa doveva succedere. Le segnalazioni di bug possono - in molti casi - essere chiaramente definite come un problema di test case. In effetti, dalla mia esperienza, definire il bug come un caso di test rotto rende la discussione molto, molto più semplice.

Anziché ascoltare gli esperti, cercare di spiegare un processo aziendale super complesso, gli esperti devono produrre esempi concreti del processo.

TDD richiede che i requisiti siano corretti al 100%. In tali casi, ci si potrebbe aspettare che requisiti contrastanti vengano catturati durante la creazione di test. Ma il problema è che questo non è il caso in uno scenario complesso.

Non utilizzare TDD impone assolutamente che i requisiti siano corretti al 100%. Alcuni sostengono che TDD può tollerare requisiti incompleti e mutevoli, in cui un approccio non TDD non può funzionare con requisiti incompleti.

Se non si utilizza TDD, la contraddizione si trova in ritardo nella fase di implementazione.

Se si utilizza TDD la contraddizione viene rilevata precedente quando il codice supera alcuni test e fallisce altri test. In effetti, TDD fornisce prova di una contraddizione all'inizio del processo, molto prima dell'implementazione (e argomenti durante il test di accettazione dell'utente).

Hai un codice che supera alcuni test e ne fallisce altri. Guardi solo quei test e trovi la contraddizione. Funziona davvero, molto bene in pratica perché ora gli utenti devono discutere della contraddizione e produrre esempi coerenti e concreti del comportamento desiderato.

52
S.Lott

Si

La mia prima esposizione a TDD stava lavorando sui componenti middleware per un telefono cellulare basato su Linux. Ciò alla fine è finito per essere milioni di righe di codice sorgente, che a sua volta ha richiamato in circa 9 gigabyte di codice sorgente per vari componenti open source.

Tutti gli autori di componenti dovevano proporre sia un'API che una serie di test unitari e farli revisionare il progetto da un comitato inter pares. Nessuno si aspettava la perfezione nei test, ma tutte le funzioni esposte pubblicamente dovevano avere almeno un test e una volta che un componente veniva sottoposto al controllo del codice sorgente, tutti i test unitari dovevano sempre passare (anche se lo facevano perché il componente riportava erroneamente ha funzionato bene).

Senza dubbio, almeno in parte a causa del TDD e dell'insistenza sul fatto che tutti i test unitari passano sempre, la versione 1.0 è arrivata in anticipo, sotto budget e con una stabilità sorprendente.

Dopo la versione 1.0, poiché l'azienda voleva essere in grado di cambiare rapidamente l'ambito a causa delle richieste dei clienti, ci ha detto di smettere di fare TDD e ha rimosso il requisito che i test unitari superano. È stato sorprendente quanto velocemente la qualità sia andata in bagno, e poi il programma l'ha seguita.

28
Bob Murphy

Direi che più complesso è il progetto, maggiore sarà il vantaggio che otterrai dal TDD. I principali vantaggi sono gli effetti collaterali di come TDD ti costringerà a scrivere il codice in blocchi molto più piccoli e molto più indipendenti. I vantaggi principali sono:

a) Ottieni molto, molto prima convalida del tuo progetto perché il tuo circuito di feedback è molto più stretto a causa dei test fin dall'inizio.

b) Puoi cambiare bit e pezzi e vedere come reagisce il sistema perché hai creato una trapunta di copertura di test per tutto il tempo.

c) Il codice finito sarà di conseguenza molto migliore.

18
Wyatt Barnett

TDD funziona davvero per progetti complessi?
Sì. Non tutti i progetti, quindi mi è stato detto che funzionano bene con TDD, ma la maggior parte delle applicazioni aziendali vanno bene e scommetto che quelle che non funzionano bene quando sono scritte in modo TDD puro potrebbero essere scritte in modo ATDD senza problemi importanti.

Generazione e gestione di dati fittizi
Tenerlo piccolo e avere solo ciò di cui hai bisogno e questo non è il problema spaventoso che sembra. Non fraintendetemi, è un dolore. Ma vale la pena.

Testing GUI
Prova MVVM e assicurati che possa essere testato senza la vista. Non l'ho trovato più difficile del testare qualsiasi altra logica aziendale. Testare la vista nel codice non lo faccio, tutto ciò che stai testando, tuttavia, a questo punto è una logica vincolante, che si spera venga catturata rapidamente quando si esegue un rapido test manuale.

Test del business
Non è stato riscontrato un problema. Molti piccoli test. Come ho detto sopra, alcuni casi (i risolutori di puzzle di Sudoku sembrano essere popolari) sono apparentemente difficili da fare TDD.

TDD richiede che i requisiti siano corretti al 100%
No non lo fa. Da dove hai preso questa idea? Tutte le pratiche Agile accettano che i requisiti cambino. Devi sapere cosa stai facendo prima di farlo, ma non è lo stesso che richiedere che i requisiti siano al 100%. TDD è una pratica comune in Scrum, in cui i requisiti (User Story) sono, per definizione, non completi al 100%.

10
mlk

Prima di tutto, credo che il tuo problema riguardi più i test unitari in generale del TDD, dal momento che non vedo nulla di specifico in TDD (test-first + red-green-refactor cycle) in quello che dici.

È difficile e non realistico mantenere grandi dati fittizi.

Cosa intendi con dati fittizi? Si suppone che un simulatore contenga a malapena dati, vale a dire nessun campo diverso da uno o due necessari nel test e nessuna dipendenza diversa dal sistema in esame. L'impostazione di una finta aspettativa o valore di ritorno può essere fatta in una riga, quindi niente di terribile.

È ancora più difficile quando la struttura del database subisce modifiche.

Se intendi che il database subisce modifiche senza che siano state apportate le modifiche appropriate al modello a oggetti, anche i test unitari sono proprio qui per avvisarti di ciò. Altrimenti, le modifiche al modello devono riflettersi ovviamente nei test unitari, ma con indicazioni di compilazione è una cosa facile da fare.

Anche con MVVM e la capacità di testare la GUI, ci vuole molto codice per riprodurre lo scenario della GUI.

Hai ragione, testare l'unità della GUI (View) non è facile e molte persone stanno andando bene senza di essa (inoltre, testare la GUI non fa parte di TDD). Al contrario, test unitari del Controller/Presenter/ViewModel/qualunque sia lo strato intermedio è altamente raccomandato, in realtà è uno dei motivi principali che sono modelli come MVC o MVVM.

Ho esperienza che TDD funziona bene se lo si limita a una semplice logica aziendale. Tuttavia, la logica aziendale complessa è difficile da testare poiché il numero di combinazioni di test (spazio di test) è molto elevato.

Se la logica aziendale è complessa, è normale che i test unitari siano difficili da progettare. Spetta a voi renderli il più atomici possibile, ciascuno testando solo una responsabilità dell'oggetto in prova. I test unitari sono tanto più necessari in un ambiente complesso perché forniscono una rete di sicurezza che garantisce di non infrangere le regole o i requisiti aziendali quando si apportano modifiche al codice.

TDD richiede che i requisiti siano corretti al 100%.

Assolutamente no. Un software di successo richiede che i requisiti siano corretti al 100%;) I test unitari riflettono solo la tua visione dei requisiti attualmente; se la visione è imperfetta, lo saranno anche il tuo codice e il tuo software, unit test o no ... Ed è qui che brillano i test unitari: con titoli di test abbastanza espliciti, le tue decisioni di progettazione e l'interpretazione dei requisiti diventano trasparenti, il che semplifica l'individuazione il tuo dito su ciò che deve essere cambiato la prossima volta che il tuo cliente dice "questa regola aziendale non è esattamente come vorrei".

9
guillaume31

Devo ridere quando sento qualcuno lamentarsi che la ragione per cui non possono usare TDD per testare la loro applicazione è perché la loro applicazione è così complicata. Qual è l'alternativa? Le scimmie test hanno martellato su acri di tastiere? Consentire agli utenti di essere i tester? Cos'altro? Certo, è difficile e complesso. Pensi che Intel non collauda i propri chip fino alla loro spedizione? Quanto è "testa nella sabbia"?

6
SnoopDougieDoug
> Does TDD really work for complex projects?

Dalla mia esperienza: Sì per Unittests (test di moduli/funzionalità in isolamento) perché questi per lo più non hanno i problemi che menzioni: (Gui, Mvvm, Business-Modell). Non ho mai avuto più di 3 mock/stub per riempire un unittest (ma forse il tuo dominio richiede di più).

Comunque sono non shure se TDD potesse risolvere i problemi che hai menzionato sull'integrazione o test end-to-end con test in stile BDD.

Ma almeno alcuni problemi possono essere ridotti.

> However complex business logic is hard to test since the number 
> of combinations of tests (test space) is very large.

Ciò è vero se si desidera eseguire una copertura completa a livello di test di integrazione o test end-to-end. Potrebbe essere più semplice eseguire la copertura completa a un livello più semplice.

Esempio: controllo di autorizzazioni utente complesse

Testare la funzione IsAllowedToEditCusterData() a livello di test di integrazione richiederebbe di chiedere a oggetti diversi informazioni su utente, dominio, cliente, ambiente .....

Deridere queste parti è abbastanza difficile. Ciò è particolarmente vero se IsAllowedToEditCusterData() deve conoscere questi diversi oggetti.

A livello di Unittest avresti la funzione IsAllowedToEditCusterData() che prende ad esempio 20 parametri che contengono tutto ciò che la funzione deve sapere. Poiché IsAllowedToEditCusterData() non ha bisogno di sapere quali campi un user, un domain, un customer, .... questo è facile da testare.

Quando ho dovuto implementare IsAllowedToEditCusterData() ho avuto due sovraccarichi:

Un sovraccarico che non fa altro che ottenere quei 20 parametri e quindi chiamare il sovraccarico con i 20 parametri che fanno il processo decisionale.

(il mio IsAllowedToEditCusterData() aveva solo 5 parametri e avevo bisogno di 32 combinazioni diverse per testarlo completamente)

Esempio

// method used by businesslogic
// difficuilt to test because you have to construct
// many dependant objects for the test
public boolean IsAllowedToEditCusterData() {
    Employee employee = getCurrentEmployee();
    Department employeeDepartment = employee.getDepartment();
    Customer customer = getCustomer();
    Shop shop = customer.getShop();

    // many more objects where the permittions depend on

    return IsAllowedToEditCusterData(
            employee.getAge(),
            employeeDepartment.getName(),
            shop.getName(),
            ...
        );
}

// method used by junittests
// much more easy to test because only primitives
// and no internal state is needed
public static boolean IsAllowedToEditCusterData(
        int employeeAge,
        String employeeDepartmentName,
        String shopName,
        ... ) 
{
    boolean isAllowed; 
    // logic goes here

    return isAllowed;
}
4
k3b

Ho trovato TDD (e test unitari in generale) praticamente impossibili per un motivo correlato: algoritmi complessi, nuovi e/o fuzzy. Il problema che incontro di più nei prototipi di ricerca che scrivo è che non ho idea di quale sia la risposta giusta se non eseguendo il mio codice. È troppo complicato da capire ragionevolmente a mano per casi tutt'altro che ridicolmente banali. Ciò è particolarmente vero se l'algoritmo prevede euristica, approssimazioni o non determinismo. Cerco ancora di testare la funzionalità di livello inferiore da cui dipende questo codice e che asserisce fortemente come controlli di integrità. Il mio ultimo metodo di test è quello di scrivere due diverse implementazioni, idealmente in due lingue diverse usando due diversi set di librerie e confrontare i risultati.

4
dsimcha

La triste risposta è che nulla funziona davvero per grandi progetti complessi!

TDD è buono come qualsiasi altra cosa e migliore della maggior parte, ma TDD da solo non garantirà il successo in un grande progetto. Aumenterà tuttavia le tue possibilità di successo. Soprattutto se utilizzato in combinazione con altre discipline di gestione del progetto (verifica dei requisiti, casi d'uso, matrice di tracciabilità dei requisiti, procedure dettagliate per il codice ecc.).

3
James Anderson

Ho visto un grande progetto complesso fallire completamente quando TDD è stato utilizzato esclusivamente, cioè senza almeno essere impostato in un debugger/IDE. I dati fittizi e/o i test si sono rivelati insufficienti. I dati reali dei client Beta erano sensibili e non potevano essere copiati o registrati. Quindi, il team di sviluppo non ha mai potuto correggere i bug fatali che si manifestavano quando venivano puntati su dati reali, e l'intero progetto è stato demolito, tutti licenziati, tutto sommato.

Il modo per risolvere questo problema sarebbe stato quello di accenderlo in un debugger sul sito client, confrontarsi con i dati reali, scorrere il codice, con punti di interruzione, variabili di controllo, memoria di controllo, ecc. Tuttavia, questo team, che pensavano che il loro codice fosse adatto per abbellire le più belle torri d'avorio, per un periodo di quasi un anno non avevano mai acceso la loro app. Mi ha fatto impazzire.

Quindi, come tutto, l'equilibrio è la chiave. TDD può essere buono ma non fare affidamento esclusivamente su di esso.

1
SPA

Ricorda che i test unitari sono specifiche applicate. Ciò è particolarmente utile in progetti complessi. Se la tua vecchia base di codice non ha test per eseguirne il backup, nessuno oserà cambiare nulla perché avrà paura di rompere qualcosa.

"Wtf. Perché questo ramo di codice è anche lì? Non lo so, forse qualcuno ne ha bisogno, è meglio lasciarlo lì piuttosto che turbare qualcuno ..." Nel corso del tempo i progetti complessi diventano una terra spazzatura.

Con i test, chiunque può dire con sicurezza "Ho fatto cambiamenti drastici, ma tutti i test stanno ancora superando". Per definizione, non ha rotto nulla. Questo porta a progetti più agili che possono evolversi. Forse uno dei motivi per cui abbiamo ancora bisogno di persone per mantenere COBOL è perché i test non erano popolari da allora: P

1
kizzx2

Se la combinazione di budget, requisiti e capacità del team si trova nel quadrante dello spazio del progetto, marcato "abbandona la speranza tutti coloro che entrano qui", per definizione è estremamente probabile che il progetto fallisca.

Forse i requisiti sono complessi e volatili, l'infrastruttura instabile, il team junior e con un elevato turnover, o l'architetto è un idiota.

In un progetto TDD, il sintomo di questo fallimento imminente è che i test non possono essere scritti nei tempi previsti; ci provi, solo per scoprire 'che ci vorrà questo lungo, e abbiamo solo quello'.

Altri approcci mostreranno sintomi diversi quando falliscono; più comunemente consegna di un sistema che non funziona. Politica e contratti determineranno se ciò è preferibile.

0
soru

Penso di sì, vedi Test Driven Development funziona davvero

Nel 2008, Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat e Laurie Williams hanno scritto un documento intitolato "Realizzare il miglioramento della qualità attraverso lo sviluppo test-driven: risultati ed esperienze di quattro team industriali" (collegamento PDF). L'abstract:

Lo sviluppo guidato dai test (TDD) è una pratica di sviluppo software che è stata utilizzata sporadicamente per decenni. Con questa pratica, un ingegnere del software passa ciclicamente minuto per minuto tra la scrittura di test unitari non riusciti e la scrittura di codice di implementazione per superare tali test. Lo sviluppo guidato dai test è recentemente riemerso come pratica abilitante fondamentale per metodologie di sviluppo software agili. Tuttavia, poche prove empiriche supportano o confutano l'utilità di questa pratica in un contesto industriale. Sono stati condotti casi di studio con tre team di sviluppo di Microsoft e uno di IBM che hanno adottato TDD. I risultati dei casi studio indicano che la densità del difetto di pre-rilascio dei quattro prodotti è diminuita tra il 40% e il 90% rispetto a progetti simili che non hanno utilizzato la pratica TDD. Soggettivamente, i team hanno riscontrato un aumento del 15–35% nei tempi di sviluppo iniziale dopo l'adozione del TDD.

Nel 2012, Ruby on Rails assumono TDD. Mi affido personalmente a strumenti come rspec per scrivere test e simulazioni, factory_girl per creare oggetti, capybara per browser automazione, semplice per la copertura del codice e protezione per l'automazione di questi test.

Come risultato dell'utilizzo di questa metodologia e di questi strumenti, tendo a concordare soggettivamente con Nagappan et al ...

0
Hiltmon