E 'una buona idea misurare le prestazioni di un metodo usando il timeout del test dell'unità?

12

In un progetto in cui sono presenti requisiti non funzionali che specificano il tempo massimo di esecuzione per un'azione specifica, QA deve verificare le prestazioni di questa azione su una macchina dedicata utilizzando hardware preciso sotto carico preciso, sia l'hardware che il carico sono specificati nei requisiti.

D'altra parte, alcune errate modifiche al codice sorgente potrebbero avere un impatto negativo sulle prestazioni. Notare questo impatto negativo in anticipo , prima il codice sorgente raggiunge il controllo del codice sorgente ed è verificato dal dipartimento QA, potrebbe essere utile in termini di tempo perso dal reparto QA che segnala il problema, e dallo sviluppatore che lo aggiusta più volte più tardi.

Per fare ciò, è una buona idea:

  • Per utilizzare i test unitari per avere un'idea del tempo impiegato per eseguire la stessa azione n volte,

  • Per utilizzare timeout per test tramite l'attributo [TestMethod, Timeout(200)] in C #?

Mi aspetto diversi problemi con questo approccio:

  • Concettualmente , i test unitari non sono proprio per questo: ci si aspetta che testino una piccola parte di un codice, nient'altro: né il controllo di un requisito funzionale, né un test di integrazione , né un test delle prestazioni.

  • Il timeout del test dell'unità in Visual Studio misura davvero cosa ci si aspetta che venga misurato, tenendo conto che l'inizializzazione e la pulizia sono inesistenti per quei test o sono troppo brevi per influenzare i risultati?

  • Misurare le prestazioni in questo modo è brutto. Eseguire un benchmark su qualsiasi macchina¹ indipendentemente dall'hardware, dal carico, ecc. È come fare un benchmark che mostri che uno il prodotto del database è sempre più veloce di un altro. D'altra parte, non mi aspetto che questi test unitari siano un risultato definitivo, né qualcosa che viene utilizzato dal dipartimento QA . Questi test unitari saranno usati solo per dare un'idea generale delle prestazioni attese, ed essenzialmente per avvisare lo sviluppatore che la sua ultima modifica ha rotto qualcosa, influenzando gravemente le prestazioni .

  • TDD è impossibile per quei test. Come fallirebbe, in primo luogo, prima di iniziare a implementare il codice?

  • Troppi test delle prestazioni influenzeranno il tempo richiesto per eseguire i test, quindi questo approccio è limitato solo a azioni brevi.

Tenendo conto di questi problemi, trovo ancora interessante utilizzare questi test unitari se combinati con le metriche delle prestazioni reali del dipartimento QA.

Mi sbaglio? Ci sono altri problemi che rendono totalmente inaccettabile l'uso dei test unitari per questo?

Se ho torto, qual è il modo corretto per avvisare lo sviluppatore che un cambiamento nel codice sorgente ha seriamente compromesso le prestazioni, prima che il codice sorgente raggiunga il controllo del codice sorgente e sia verificato dal dipartimento QA?

¹ In realtà, i test unitari dovrebbero funzionare solo su PC per sviluppatori con prestazioni hardware paragonabili, il che riduce il divario tra le macchine più veloci che non saranno mai in grado di fallire il test delle prestazioni e le macchine più lente che non riuscire mai a passarlo.

² Per azione intendo un pezzo di codice piuttosto breve che impiega alcuni millisecondi per essere eseguito.

    
posta Arseni Mourzenko 16.01.2012 - 01:56
fonte

4 risposte

2

Stiamo utilizzando anche questo approccio, ovvero abbiamo test che misurano il tempo di esecuzione in uno scenario di carico definito su una determinata macchina. Potrebbe essere importante sottolineare che non li includiamo nei normali test unitari. I test unitari vengono fondamentalmente eseguiti da ogni sviluppatore su una macchina sviluppatore prima di eseguire le modifiche. Vedi sotto per il motivo per cui questo non ha senso per i test delle prestazioni (almeno nel nostro caso). Al contrario, eseguiamo test delle prestazioni come parte dei test di integrazione.

Hai correttamente sottolineato che questo non dovrebbe escludere la verifica. Non riteniamo che il nostro test sia un test del requisito non funzionale. Invece, lo consideriamo un semplice indicatore di potenziale-errore.

Non sono sicuro del tuo prodotto, ma nel nostro caso, se le prestazioni sono insufficienti, significa che è necessario molto lavoro per "risolverlo". Quindi il tempo di consegna, quando lasciamo tutto questo a QA è orribile. Inoltre, le correzioni delle prestazioni avranno gravi ripercussioni su gran parte del code-base, il che rende nullo il precedente QA. Tutto sommato, un flusso di lavoro molto inefficiente e insoddisfacente.

Detto questo, ecco alcuni punti per i tuoi rispettivi problemi:

  • concettualmente: è vero che non si tratta di test unitari. Ma finché tutti sanno che il test non dovrebbe verificare tutto ciò che il QA dovrebbe fare, va bene.

  • Visual Studio: non posso dire nulla a riguardo, poiché non usiamo il quadro di test unitario di VS.

  • Macchina: dipende dal prodotto. Se il tuo prodotto è qualcosa sviluppato per gli utenti finali con macchine desktop individuali personalizzate, allora è più realistico eseguire i test su macchine di diversi sviluppatori. Nel nostro caso, consegniamo il prodotto per una macchina con una determinata specifica e eseguiamo questi test delle prestazioni solo su una macchina del genere. In effetti, non ha molto senso misurare le prestazioni sulla tua macchina per sviluppatori dual-core, quando il client alla fine eseguirà 16 o più core.

  • TDD: sebbene l'errore iniziale sia tipico, non è obbligatorio. In effetti, scrivere questi test in anticipo lo rende più un test di regressione piuttosto che un test unitario tradizionale. Che il test abbia successo all'inizio non è un problema. Ma ottieni il vantaggio, che ogni volta che uno sviluppatore aggiunge funzionalità che rallentano le cose, perché non è a conoscenza del requisito di prestazione non funzionale, questo test TDD lo individuerà. Succede molto, ed è un feedback fantastico. Immagina che nel tuo lavoro quotidiano: scrivi codice, lo impegni, vai a pranzo e quando torni, il sistema di compilazione ti dice che questo codice quando viene eseguito in un ambiente con carichi pesanti è troppo lento. È abbastanza bello per me accettare che il test TDD non sia inizialmente fallito.

  • Tempo di esecuzione: come accennato, non eseguiamo questi test sui computer degli sviluppatori, ma piuttosto come parte del sistema di compilazione in una sorta di test di integrazione.

risposta data 16.01.2012 - 07:34
fonte
2

Sono per lo più in linea con il tuo pensiero. Sto semplicemente mettendo il mio ragionamento con un flusso indipendente.

1. Fallo funzionare prima di renderlo migliore / più veloce Prima che il codice fornisca qualsiasi misura di prestazione (per non parlare della garanzia) dovrebbe prima essere corretto , cioè renderlo funzionalmente funzionante. Ottimizzare il codice che è funzionalmente sbagliato non è solo una perdita di tempo, ma pone degli ostacoli allo sviluppo.

2. Le prestazioni di un sistema hanno senso solo sul sistema completo
In genere, qualsiasi prestazione significativa dipende sempre da una determinata infrastruttura e dovrebbe essere vista solo con un sistema completo. Ad esempio, durante il test di simulazione, se il modulo riceve risposte da un file di testo locale, ma nell'ambiente di produzione viene recuperato dal database, il precedente

3. Il ridimensionamento delle prestazioni dovrebbe essere fatto per obiettivo Una volta ottenuto il sistema funzionale, è necessario analizzare le prestazioni del sistema e individuare i colli di bottiglia per capire dove è necessario aumentare le prestazioni. Cercando ciecamente di ottimizzare ogni metodo anche prima di sapere che le prestazioni di un sistema completo possono incorrere in inutili quantità di lavoro (ottimizzando i metodi che non contano) e possono creare inutilmente il tuo codice gonfiato.

Non sono consapevole delle funzionalità di Visual Studio, ma in genere è necessario uno strumento di profilazione più ampio.

    
risposta data 16.01.2012 - 07:45
fonte
2

Ho avuto un'attività simile qualche tempo fa e la soluzione finale era da qualche parte nel mezzo tra test unitari e test delle prestazioni automatizzati in piena regola.

Alcune considerazioni in nessun ordine particolare, che può essere utile:

  • Il test delle prestazioni eseguito da QA richiedeva molto tempo e aveva un proprio programma (ad esempio, una volta nell'iterazione), quindi il controllo del codice sorgente non era un problema.
  • Il nostro sistema era ampio e modulare, i test unitari erano troppo granulari per le nostre esigenze e abbiamo creato speciali test unitari "grassi" attentamente elaborati per innescare problemi di prestazioni nelle specifiche aree di interesse (erano anche classificati, ma questo è un dettaglio di implementazione).
  • I vincoli usuali per i test unitari si applicano ancora: dovrebbero essere piccoli, veloci e al punto.
  • Per escludere l'influenza del framework di test, erano eseguiti da uno speciale wrapper, quindi sapevamo esattamente quanto tempo impiega l'operazione.
  • È possibile scriverli prima che l'implementazione effettiva sia completa (i risultati potrebbero essere irrilevanti o utili, a seconda del processo, forse gli sviluppatori stanno ancora sperimentando l'implementazione e vorrebbe vedere come andrà nel suo complesso).
  • Erano eseguiti dal server CI dopo la ogni build, quindi il tempo di esecuzione totale dovrebbe essere relativamente breve (se non è così, diventa molto più difficile individuare la modifica esatta che ha causato il problema).
  • Il server CI era potente e aveva il suo hardware riparato, quindi lo contammo come macchina dedicata (è possibile usare un server veramente dedicato usando un agente di compilazione remoto).
  • Il wrapper del test ha raccolto tutte le informazioni rilevanti (specifiche hardware, nomi / categorie di test, carico del sistema, tempo trascorso, ecc.) ed è stato esportato come report o nel database.
  • Abbiamo avuto un gadget per JIRA che estraeva tali rapporti e disegnava dei grafici carini per nome / categoria / numero di build con alcuni controlli (sovrapponeva la versione precedente alla versione corrente, ecc.), in modo che gli sviluppatori possano vedere rapidamente il loro impatto e i gestori possano ottieni una panoramica (un po 'di rosso, tutto verde, sai, è importante per loro).
  • È stato possibile analizzare come il progetto sta andando nel tempo utilizzando le statistiche raccolte.

Quindi, alla fine, disponevamo di un sistema scalabile, flessibile e prevedibile che possiamo rapidamente mettere a punto per i nostri requisiti speciali. Ma ha richiesto alcuni sforzi per implementare.

Ritornando alle domande. Concettualmente i test unitari non sono per questo, ma puoi sfruttare le funzionalità del tuo framework di test. Non ho mai considerato i timeout di test come un mezzo per misurare, è solo una rete di sicurezza per appendere e cose del genere. Ma se il tuo attuale approccio funziona per te, allora continua ad usarlo, sii pratico. Puoi sempre andare in secondo piano, se necessario.

    
risposta data 16.01.2012 - 08:45
fonte
0

Penso che tu stia bene. Questo è esattamente il punto di avere timeout di test unitario: per verificare se qualcosa sta prendendo modo, modo più a lungo di quanto dovrebbe. Esistono limitazioni a questo approccio, ma sembra che tu ne sia già a conoscenza, quindi se tieni a mente queste limitazioni, non vedo alcun problema.

    
risposta data 16.01.2012 - 04:23
fonte