Accelerare i test RSpec in una grande applicazione Rails


90

Ho un'applicazione Rails con oltre 2.000 esempi nei miei test RSpec. Inutile dire che è un'applicazione di grandi dimensioni e c'è molto da testare. L'esecuzione di questi test a questo punto è molto inefficiente e poiché ci vuole così tanto tempo, siamo quasi sul punto di essere scoraggiati dallo scriverli prima di spingere una nuova build. Ho aggiunto --profile al mio spec.opts per trovare gli esempi più lunghi e ce ne sono almeno 10 che richiedono una media di 10 secondi per essere eseguiti. È normale tra voi esperti RSpec? 10 secondi sono troppo lunghi per un esempio? Mi rendo conto che con 2.000 esempi, ci vorrà una quantità di tempo non banale per testare tutto a fondo, ma a questo punto 4 ore sono un po 'ridicole.

Che tipo di volte stai vedendo per i tuoi esempi più longevi? Cosa posso fare per risolvere i problemi delle mie specifiche esistenti al fine di individuare i colli di bottiglia e accelerare le cose. Ogni minuto sarebbe davvero utile a questo punto.


1
I test lenti sono test di integrazione? Stanno colpendo un db? In tal caso, con che frequenza viene ricaricato il db e puoi deridere il db?
Kaleb Pederson

1
Sei in grado di eseguire solo una parte delle specifiche rilevanti per la parte su cui stai lavorando, simile all'autotest di SeattleRB? Hai un server di integrazione continua in grado di eseguire tutti i test?
Andrew Grimm

Ricorda anche che tutte le cose sono relative. Ho sentito "grrr, la nostra suite di test dura un'eternità" sia per 20 minuti ... che per 16-20 ore. È tutto negli occhi di chi guarda. 10 secondi per un determinato test spesso indicano uno unit test che è diventato un test di integrazione come indicato di seguito.
Michael Durrant

Un suggerimento per questo tipo di problema: usalo perftools.rbinsieme al tuo framework di test per capire cosa sta consumando la maggior parte del tuo tempo. Rispondi alle prime 10 chiamate e cerca di eliminarle / scremarle. Quindi ripeti, finché non sei felice.
aledalgrande

Risposte:


118

10 secondi sono un tempo molto lungo per l'esecuzione di un singolo test. La mia sensazione viscerale è che il tuo obiettivo specifico stia eseguendo test di unità e di integrazione contemporaneamente. Questa è una cosa tipica in cui cadono i progetti e ad un certo punto, dovrai superare questo debito tecnico se vuoi produrre di più, più velocemente. Ci sono una serie di strategie che possono aiutarti a farlo ... e ne consiglierò alcune che ho usato in passato.

1. Separare l'unità dai test di integrazione

La prima cosa che vorrei fare è separare l'unità dai test di integrazione. Puoi farlo in uno dei seguenti modi:

  1. Spostandoli (in cartelle separate nella directory spec) e modificando i target di rake
  2. Taggarli (rspec ti consente di taggare i tuoi test)

La filosofia è che vuoi che le tue build regolari siano veloci, altrimenti le persone non saranno troppo felici di eseguirle spesso. Quindi torna in quel territorio. Fai in modo che i tuoi test regolari vengano eseguiti rapidamente e utilizza un server di integrazione continua per eseguire la build più completa.

Un test di integrazione è un test che coinvolge dipendenze esterne (ad esempio Database, WebService, Queue e alcuni potrebbero sostenere FileSystem). Uno unit test verifica solo l'elemento di codice specifico che si desidera controllare. Dovrebbe funzionare velocemente (9000 in 45 secondi è possibile), cioè la maggior parte dovrebbe funzionare in memoria.

2. Convertire i test di integrazione in test unitari

Se la maggior parte dei tuoi unit test è inferiore alla tua suite di test di integrazione, hai un problema. Ciò significa che le incongruenze inizieranno ad apparire più facilmente. Quindi, da qui, inizia a creare più unit test per sostituire i test di integrazione. Le cose che puoi fare per aiutare in questo processo sono:

  1. Usa un quadro beffardo invece della vera risorsa. Rspec ha un framework beffardo integrato.
  2. Esegui rcov sulla tua suite di unit test. Usalo per valutare quanto è approfondita la tua suite di unit test.

Dopo aver eseguito uno o più unit test appropriati per sostituire un test di integrazione, rimuovere il test di integrazione. I test duplicati peggiorano solo la manutenzione.

3. Non utilizzare dispositivi

Gli infissi sono malvagi. Usa invece una fabbrica (macchinista o factorybot). Questi sistemi possono creare grafici di dati più adattabili e, cosa più importante, possono creare oggetti in memoria che è possibile utilizzare, piuttosto che caricare elementi da un'origine dati esterna.

4. Aggiungere controlli per arrestare i test unitari che diventano test di integrazione

Ora che hai in atto test più veloci, è tempo di inserire controlli per FERMARE che ciò si verifichi di nuovo.

Esistono librerie in cui il record attivo della patch di scimmia genera un errore quando si tenta di accedere al database (UnitRecord).

Puoi anche provare l'associazione e il TDD che possono aiutare a costringere il tuo team a scrivere test più veloci perché:

  1. Qualcuno sta controllando, quindi nessuno diventa pigro
  2. Un TDD corretto richiede un feedback veloce. I test lenti rendono l'intera cosa dolorosa.

5. Utilizzare altre librerie per superare il problema

Qualcuno ha menzionato spork (accelera i tempi di caricamento per la suite di test sotto rails3), hydra / parallel_tests - per eseguire unit test in parallelo (su più core).

Questo dovrebbe probabilmente essere usato ULTIMO. Il tuo vero problema risiede nel passaggio 1, 2, 3. Risolvilo e sarai in una posizione migliore per sfruttare l'infrastruttura aggiuntiva.


Bella risposta. È molto vero che nessuno strumento avanzato può aiutare a eseguire rapidamente test errati. Quindi prova a scrivere solo quelli buoni.
Yura Omelchuk

5
Non sono d'accordo sul tuo terzo punto che non dovresti usare dispositivi. Se usati correttamente sono più veloci delle fabbriche in quanto non devi creare oggetti. I tuoi dati sono lì, non devi crearli con ogni caso di test.
wallerjake

3
Questo sul fatto che le fabbriche siano più veloci è uno scherzo, giusto?
Mike Szyndel

Speed Up Test selettivamente Evitare Factory Girl - robots.thoughtbot.com/...
geekdev

16

Per un ottimo libro di cucina sul miglioramento delle prestazioni della tua suite di test, dai un'occhiata alla presentazione Grease Your Suite .

Documenta un aumento di velocità di 45 volte nel tempo di esecuzione della suite di test utilizzando tecniche come:


Mi piacciono i link, ma non la presentazione. Le schede per il discorso di qualcuno sono un suggerimento per l'oratore di riempire la carne della presentazione.
Brian Maltzan

Questa presentazione non è più disponibile. fast_context accelera più blocchi shoulda. quickerclip (anche quel collegamento morto) apparentemente accelera Paperclip. Hydra è deprecato per parallel_tests e Gorgon. bootsnap ha delle modifiche al file system ed è ora incluso con Rails. Le versioni recenti di Ruby hanno migliorato l'allocazione e la GC.
rappresentante

5

Puoi usare Spork. Supporta 2.3.x,

https://github.com/sporkrb/spork

o ./script/spec_server che potrebbe funzionare per 2.x

Inoltre è possibile modificare la configurazione del database (che essenzialmente accelera le query del database, ecc.), Che aumenterà anche le prestazioni per i test.


Spork è fantastico. Funziona anche su Rails 3, con un po 'di hacking. Ma una cosa da notare con Spork on Rails 3 è che non sembra rilevare modifiche nei controller, quindi dovrai riavviarlo ogni tanto. Ma comunque, Spork è davvero fantastico, il miglioramento della velocità dei test è molto significativo.
Ruby

4
Spork serve solo ad accelerare l'avvio, non i test. Quindi, con molte specifiche, il vantaggio è insignificante.
Reactormonk

Contrariamente ai commenti sopra, spork può essere utilizzato per accelerare i test e l'avvio come da railscast railscasts.com/episodes/285-spork . Ho migliorato notevolmente la mia suite di test rspec su un'app molto grande. (Ridotto da 192 secondi a 10 secondi!)
jamesc

3

10 secondi per esempio sembrano un tempo molto lungo. Non ho mai visto una specifica che impiegasse più di un secondo e la maggior parte richiede molto meno. Stai testando le connessioni di rete? Il database scrive? Il filesystem scrive?

Usa i mock e gli stub il più possibile: sono molto più veloci della scrittura di codice che raggiunge il database. Sfortunatamente anche la presa in giro e lo stubbing richiedono più tempo per scrivere (e sono più difficili da fare correttamente). Devi bilanciare il tempo speso per scrivere i test rispetto al tempo speso per eseguire i test.

Accolgo il commento di Andrew Grimm sull'analisi di un sistema CI che potrebbe consentire di parallelizzare la suite di test. Per qualcosa di quella dimensione, potrebbe essere l'unica soluzione praticabile.


sì, se sono 10 secondi, lo profilerei e
vedrei

1
Ho un progetto enorme e l'esecuzione di un singolo test rspec richiede circa 15-20 secondi.
ExiRe

2

Diverse persone hanno menzionato Hydra sopra. Lo abbiamo utilizzato con grande successo in passato. Recentemente ho documentato il processo di installazione e funzionamento di hydra: http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/

Concordo con l'idea che questo tipo di tecnica non dovrebbe essere utilizzato come sostituto per la scrittura di test che sono ben strutturati e veloci per impostazione predefinita.





-4

Elimina la suite di test esistente. Sarà incredibilmente efficace.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.