Mi è stato chiesto come eseguire una suite di 65.000.000.000 di test e mi chiedo se sia normale avere un progetto con una quantità così grande di test.
Hai lavorato in progetti con questa caratteristica?
Mi è stato chiesto come eseguire una suite di 65.000.000.000 di test e mi chiedo se sia normale avere un progetto con una quantità così grande di test.
Hai lavorato in progetti con questa caratteristica?
Con 65 miliardi di test, sembra che ti venga chiesto di testare tutti i possibili input. Questo non è utile: essenzialmente testerai che il tuo processore funzioni correttamente, non che il tuo codice sia corretto.
Dovresti testare invece classi di equivalenza . Ciò ridurrà drasticamente la tua gamma di input di test.
Considerare anche se è possibile suddividere il sistema in pezzi più piccoli. Ogni pezzo sarà più facile da testare in isolamento, quindi sarà possibile eseguire alcuni test di integrazione che riuniranno tutti i pezzi.
Se desideri comunque essere rassicurato sul fatto che alcune di queste combinazioni di input funzionino, potresti provare a test fuzz . Otterrai alcuni dei vantaggi di testare molti input diversi, ma senza eseguire tutti i 65 miliardi di questi.
Se questa è una vera e propria suite di test, allora non ti va di lavorare su di essa.
L'intero lavoro di un tester è trovare un equilibrio tra i test abbastanza approfonditi per essere sicuro di avere i risultati "giusti" e scrivere pochi test sufficienti per poter essere eseguiti in un ragionevole lasso di tempo.
Molti test possono essere astratti in "classi di equivalenza", il che significa che anziché eseguire 3 miliardi di test, si esegue 1 che offre un ragionevole livello di sicurezza che tutti gli altri test in quella classe di equivalenza sarebbero eseguiti correttamente, se si decidesse per perdere tempo a gestirli.
Dovresti dire a chiunque stia pensando di eseguire 65 miliardi di test di cui hanno bisogno per fare un lavoro migliore, astrarre i test in classi di equivalenza.
Più che probabile, sei arrivato alla tua cifra di 65 miliardi di test calcolando tutte le possibili combinazioni di input nel sistema in prova o calcolando la complessità ciclomatica e assumendo che un test debba essere scritto per ognuno di questi percorsi di esecuzione univoci.
Non è così che vengono scritti i test reali, perché, come hanno indicato altri poster e commentatori, la potenza tecnica richiesta per eseguire 65 miliardi è sbalorditiva. Sarebbe come scrivere un test che eserciti un metodo per aggiungere due interi collegando ogni possibile permutazione di due valori a 32 bit e verificando il risultato. È una pazzia totale. È necessario tracciare la linea e identificare un sottoinsieme di tutti i possibili casi di test, che tra di loro garantirebbero che il sistema si comporti come previsto nell'intero intervallo di input. Per esempio. si prova aggiungendo alcuni numeri "ordinari", si testano alcuni scenari con numero negativo, si testano i limiti tecnici come gli scenari di overflow e si testano tutti gli scenari che dovrebbero comportare un errore. Come è stato detto, questi vari tipi di test esercitano "classi di equivalenza"; ti permettono di prendere un campione rappresentativo dei possibili input, insieme a eventuali "valori anomali" conosciuti, e di dire con estrema sicurezza che, poiché passano questi scenari, passeranno tutti gli scenari simili a questi.
Considera uno dei kata di codice di base, il generatore di numeri romani. Il compito, da eseguire usando le tecniche TDD in uno stile "dojo", è scrivere una funzione che possa accettare qualsiasi numero compreso tra 1 e 3000 e produrre il numero romano corretto per quel valore numerico.
Non risolvi questo problema scrivendo 3000 test unitari, uno alla volta, e passandoli a turno. Questa è follia; l'esercizio normalmente richiede da una a due ore e tu verrai lì per giorni testando ogni singolo valore. Invece, si diventa intelligenti. Inizi con il caso base più semplice (1 == "I"), implementalo usando una strategia "least-code" ( return "I";
), poi cerca come il codice che hai si comporterà in modo errato in un altro scenario previsto (2 == "II"). Risciacqua e ripeti; più che probabile, hai sostituito la tua implementazione iniziale con qualcosa che ripete il carattere "I" ogni volta che è necessario (come return new String('I',number);
). Ovviamente questo supererà un test per III, quindi non ti preoccupare; invece, scrivi il test per 4 == "IV", che sai che l'implementazione corrente non funzionerà correttamente.
Oppure, in uno stile più analitico, esaminate ogni decisione condizionale che è fatta dal codice (o deve essere), e scrivete un test progettato per inserire il codice per ogni possibile risultato di ciascuna decisione. Se si hanno 5 affermazioni if (ognuna con un ramo vero e falso), ognuna delle quali completamente indipendente dall'altra, si codificano 10 test, non 32. Ciascun test sarà progettato per affermare due cose su una particolare decisione possibile; per prima cosa viene presa la decisione corretta, e quindi che il codice inserito data quella condizione è corretto. Tu non codifica un test per ogni possibile permutazione delle decisioni indipendenti. Se le decisioni dipendono, è necessario testarne altre in combinazione, ma ci sono meno combinazioni di questo tipo perché alcune decisioni vengono prese solo quando un'altra decisione ha un risultato particolare.
Questo è "normale" ?, no. Dove "normale" è definito come l'esperienza media o tipica. Non posso dire di aver mai dovuto lavorare su un progetto del genere, ma sono stato in un progetto in cui uno su ogni milione di bit si sarebbe capovolto. Provare che uno era ... una sfida.
È potenzialmente necessario? Bene, ciò dipende dalle garanzie e dalle specificità del progetto. All'inizio è un po 'incredulo, ma la tua domanda è chiara su specifiche.
Come altri (MichaelT) hanno sottolineato, il tempo per completare questo compito con il test seriale rende questo poco pratico. Quindi la parallelizzazione diventa la tua prima considerazione. Quanti sistemi di test puoi lanciare a questo problema e che supporto hai per raccogliere i risultati di questi sistemi multipli?
Quali garanzie hai che il dispositivo o l'algoritmo che stai testando venga replicato in modo affidabile? Il software è abbastanza affidabile in fase di replica, ma i dispositivi hardware (soprattutto di prima generazione) possono avere problemi di produzione. In questo caso, un errore di test falso potrebbe indicare un cattivo algoritmo o il dispositivo non si è assemblato correttamente. Hai bisogno di distinguere tra questi due casi?
Dovrai anche considerare come convalidare i sistemi di test stessi. Presumendo una ragione legittima per quel numero di casi di test, avrai bisogno di molta automazione. L'automazione deve essere ispezionata per assicurarsi che non commetta errori nella generazione dei casi di test. I controlli spot per gli errori sarebbero davvero l'equivalente di trovare un ago nel pagliaio.
Questo collegamento arstechnica può o non può far capire alcune considerazioni sui test. I cluster GPU sono comunemente usati per le password di cracking a forza bruta. Quella citata nell'articolo può can cycle through as many as 350 billion guesses per second
, quindi quel tipo mette i tuoi 65B test in prospettiva. È probabile che sia un dominio diverso, ma mostra come avvicinarsi al compito da diverse angolazioni può dare una soluzione praticabile.
Non penso che sia possibile mantenere 6.5e + 10 testarlo come prima cosa, quindi eseguirli potrebbe essere discutibile. Anche i progetti più grandi, come Debian con tutti i suoi pacchetti, hanno solo diverse centinaia di milioni di SLOC in totale.
Ma se devi comunque eseguire un numero enorme di test, ci sono alcune strategie.
non eseguirli tutti. Molto probabilmente non tutti i test dipendono da ogni percorso di codice. Definisci le dipendenze tra i sottosistemi e i loro test, e tra le suite di test, e sarai in grado di eseguire solo test unitari rilevanti per una particolare modifica, solo i test di integrazione a seconda di questi test unitari, ecc.
Eseguili in parallelo. Con una base di codice così grande, probabilmente si dispone di una massiccia farm di build (di nuovo su JetBrains, un'operazione relativamente piccola, avevamo 40-50 build agent in esecuzione solo nella farm di build / integrazione continua IDEA). Poiché i test unitari sono indipendenti e i test di integrazione possono riutilizzare codice già costruito, i test sono relativamente facili da parallelizzare.
Smetti di correre presto. Se sai che una particolare suite di test dipende dal suo ragionevole funzionamento sulla correttezza di un'altra suite di test, puoi tagliare l'intera catena una volta che vedi un link fallire.
Dichiarazione di non responsabilità: non sono un tecnico collaudatore professionista. Prendi il sopra con un pizzico di sale.
Anche se ci sono stati diversi buoni suggerimenti su come provare a svignarsela con meno test, dubito seriamente che il tuo sistema abbia solo 65 miliardi di combinazioni di input. Questo è meno di 36 bit di input. Supponiamo che tu abbia già preso tutti i consigli sopra riportati.
Se ogni test impiega circa un millisecondo per essere eseguito e si distribuiscono i test su soli 10 processori (un normale PC), il test verrà eseguito in poco più di 69 giorni. Questo è un po ', ma non del tutto irragionevole. Distribuisci su 100 processori (una dozzina di normali PC o un ragionevole PC server) e i test verranno completati in meno di 7 giorni. Potresti eseguirli ogni settimana per controllare le regressioni.
Leggi altre domande sui tag testing unit-testing continuous-integration