Mi è stato chiesto come eseguire una suite di 65.000.000.000 di test e mi chiedo se sia normale avere un progetto con un numero così elevato di test.
Hai lavorato a 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 un numero così elevato di test.
Hai lavorato a progetti con questa caratteristica?
Risposte:
Con 65 miliardi di test, sembra che ti venga chiesto di testare tutti i possibili input. Questo non è utile: essenzialmente verifichi che il tuo processore funzioni correttamente, non che il tuo codice sia corretto.
Dovresti invece testare le classi di equivalenza . Ciò ridurrà drasticamente la gamma di input di test.
Considera anche se puoi suddividere il tuo sistema in pezzi più piccoli. Ogni pezzo sarà più facile da testare da solo, quindi potrai eseguire alcuni test di integrazione che riuniscono tutti i pezzi.
Se vuoi comunque avere la certezza che alcune di queste combinazioni di input funzionano, forse potresti provare il fuzz test . Otterrai alcuni dei vantaggi del test di molti input diversi, ma senza eseguirne tutti i 65 miliardi.
Se questa è una vera e propria suite di test, non vorrai avvicinarti a nulla.
L'intero compito di un tester è quello di trovare un equilibrio tra i test sufficientemente approfonditi da essere sicuri di avere i risultati "giusti" e scrivere pochi test sufficienti per poterli eseguire in un ragionevole lasso di tempo.
Molti test possono essere astratti in "classi di equivalenza", il che significa che invece di eseguire 3 miliardi di test, esegui 1 che ti dà un ragionevole livello di sicurezza che tutti gli altri test in quella classe di equivalenza verrebbero eseguiti correttamente, se decidessi di sprecare il tempo di eseguirli.
Dovresti dire a chiunque stia pensando di eseguire 65 miliardi di test che hanno bisogno di fare un lavoro migliore astrattando i test in classi di equivalenza.
Molto probabilmente, 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 ciascuno di questi percorsi di esecuzione unici.
Non è così che vengono scritti test reali, perché, come hanno indicato altri poster e commentatori, la potenza tecnica richiesta per eseguire 65 miliardii test sono sconcertanti. Sarebbe come scrivere un test che eserciti un metodo per aggiungere due numeri interi collegando ogni possibile permutazione di due valori a 32 bit e controllando il risultato. È una follia assoluta. Devi tracciare la linea e identificare un sottoinsieme di tutti i possibili casi di test, che tra loro assicurerebbero che il sistema si comporti come previsto in tutta la gamma di input. Per esempio. si verifica l'aggiunta di alcuni numeri "ordinari", si verificano alcuni scenari con numeri negativi, si verificano limiti tecnici come scenari di overflow e si verifica qualsiasi scenario che dovrebbe causare errori. Come accennato, questi vari tipi di test esercitano "classi di equivalenza"; ti consentono di prelevare un campione rappresentativo dei possibili input, insieme a eventuali "valori anomali" noti,
Considera uno dei kata in codice di base, il generatore di numeri romani. Il compito, da eseguire usando le tecniche TDD in 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 unit test, uno alla volta, e superandoli a turno. Questa è follia; l'esercizio normalmente dura tra una e due ore e saresti lì per giorni a testare ogni singolo valore. Invece, diventi intelligente. Si inizia con il caso base più semplice (1 == "I"), si implementa quello usando una strategia di "codice minimo" ( return "I";
), quindi si cerca come il codice che si comporterà in modo errato in un altro scenario previsto (2 == " II "). Risciacqua e ripeti; molto probabilmente, hai sostituito la tua implementazione iniziale con qualcosa che ripete il carattere "I" tutte le volte che è necessario (come return new String('I',number);
). Questo ovviamente supererà un test per III, quindi non ti preoccupare; invece scrivi il test per 4 == "IV", che sai che l'attuale implementazione ha vinto "
Oppure, in uno stile più analitico, si esamina ogni decisione condizionale che viene presa dal codice (o deve essere) e si scrive un test progettato per inserire il codice per ogni possibile risultato di ogni decisione. Se hai 5 istruzioni if (ognuna con un ramo vero e falso), ognuna completamente indipendente dall'altra, codifichi 10 test, non 32. Ogni test sarà progettato per affermare due cose su una particolare decisione possibile; prima che sia presa la decisione corretta, e poi che il codice inserito dato quella condizione sia corretto. Lei non codificare un test per ogni possibile permutazione delle decisioni indipendenti. Se le decisioni dipendono, allora devi testarne di più in combinazione, ma ci sono meno combinazioni di questo tipo perché alcune decisioni vengono prese solo quando un'altra decisione ha avuto un risultato particolare.
Questo è "normale" ?, no. Dove "normale" è definito come esperienza media o tipica. Non posso dire di aver mai dovuto lavorare su un progetto del genere, ma sono stato su un progetto in cui uno su qualche milione di bit verrebbe lanciato. Testare quello era ... una sfida.
È potenzialmente richiesto? Bene, ciò dipende dalle garanzie e dalle specifiche del progetto. All'inizio è un po 'incredulo capire, ma la tua domanda è leggera sui dettagli.
Come altri (MichaelT) hanno sottolineato, il tempo necessario per completare questa attività con i test seriali lo rende poco pratico. Quindi la parallelizzazione diventa la tua prima considerazione. Quanti sistemi di test puoi lanciare a questo problema e quale 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 nella replica, ma i dispositivi hardware (specialmente la prima generazione) possono avere problemi di produzione. Un errore di test falso in quel caso potrebbe indicare un algoritmo errato o il dispositivo non si è assemblato correttamente. Devi distinguere tra questi due casi?
Dovrai anche considerare come convalidare i sistemi di test stessi. Presumendo una ragione legittima per molti casi di test, avrai bisogno di molta automazione. Tale automazione deve essere ispezionata per assicurarsi che non si verifichi un errore nella generazione dei casi di test. I controlli a campione per errori sarebbero davvero l'equivalente di trovare un ago nel pagliaio.
Questo link arstechnica può fornire o meno informazioni dettagliate sulle considerazioni relative ai test. I cluster GPU sono comunemente usati per le password di cracking a forza bruta. Quello citato nell'articolo può can cycle through as many as 350 billion guesses per second
, quindi quel tipo di prospettiva mette i tuoi test 65B. È probabilmente un dominio diverso, ma mostra come avvicinarsi all'attività da diverse angolazioni può produrre una soluzione praticabile.
Non credo sia possibile mantenere i test 6.5e + 10 al primo posto, 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 relativi test e tra le suite di test e sarai in grado di eseguire solo test unitari relativi a una particolare modifica, solo test di integrazione in base a questi test unitari, ecc.
Eseguili in parallelo. Con una base di codice così grande, probabilmente hai una massiccia farm di build (tornando a JetBrains, un'operazione relativamente piccola, avevamo solo 40-50 agenti di build in esecuzione sulla farm di build / integrazione continua IDEA). Poiché i test unitari sono indipendenti e i test di integrazione possono riutilizzare il codice già creato, i test sono relativamente facili da parallelizzare.
Smetti di correre presto. Se sai che una particolare suite di test dipende dal suo ragionevole funzionamento dalla correttezza di un'altra suite di test, puoi tagliare l'intera catena quando vedi che un collegamento fallisce.
Disclaimer: non sono un ingegnere di test professionale. Prendi quanto sopra con un granello di sale.
Sebbene ci siano stati molti buoni suggerimenti qui su come provare a passare di soppiatto con meno test, dubito seriamente che il tuo sistema abbia solo 65 miliardi di combinazioni di input. Sono meno di 36 bit di input. Supponiamo che tu abbia già preso tutti i consigli di cui sopra.
Se l'esecuzione di ogni test richiede circa un millisecondo e si distribuiscono i test su solo 10 processori (un PC normale), 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 PC normali o un PC server ragionevole) e i test verranno completati in meno di 7 giorni. È possibile eseguirli ogni settimana per verificare la presenza di regressioni.