Nozioni di base su AntiPattern Test di Rails

Questo articolo è un'introduzione alle acque avanzate di test di AntiPattern in Rails. Se sei un po 'nuovo per lo sviluppo basato sui test e vuoi raccogliere un paio di best practice molto preziose, questo articolo è stato scritto esattamente per te.

Temi

  • Permettere
  • Ospiti misteriosi
  • Test oscuri 
  • Test lenti
  • infissi
  • Test fragili
  • Attributi dei dati

Permettere

descrivere Mission do let (: james_bond) build_stubbed (: agente, nome: 'James Bond', numero: '007') let (: mission) build_stubbed (: missione, titolo: 'Moonraker') ... fine

Il permettere Il metodo helper in RSpec viene utilizzato molto frequentemente per creare variabili di istanza disponibili tra più test. Come uno studente desideroso di pratiche TDD, probabilmente hai scritto la tua giusta parte di questi, ma seguire questa pratica può facilmente portare ad avere un sacco di ospiti misteriosi che si mostrano-vedi sotto-che non è assolutamente qualcosa di cui abbiamo bisogno per avere un incidente alla nostra festa! 

Questo particolare effetto collaterale di permettere ha guadagnato un po 'di reputazione per aver probabilmente causato una maggiore manutenzione del test e una leggibilità inferiore in tutta la suite di test. permettere Sicuramente suona allettante perché è pigramente valutato e aiuta ad aderire al concetto di zero-difetti di DRY e tutti. Quindi sembra troppo bello non usarlo regolarmente. Il suo cugino stretto soggetto dovrebbe anche essere evitato la maggior parte del tempo.

Diventa peggio quando inizi a nidificare queste cose. permettere affermazioni intonacate di tutto annidate descrivere i blocchi sono i preferiti di tutti i tempi. Penso che non sia ingiusto chiamarla una ricetta per impiccarsi, rapidamente. Un ambito più limitato è generalmente più facile da capire e da seguire. 

Non vogliamo costruire un castello di carte con dispositivi semi-globali che oscurino la comprensione e aumentino le possibilità di interrompere i test correlati. Le probabilità di un codice di qualità artigianale sono impilate contro di noi con un tale approccio. Estrarre l'installazione di oggetti comuni è anche più facile da fare tramite semplici vecchi metodi di rubino o anche classi se necessario.

Questo permettere creatura è una soluzione ampiamente condivisa che spesso deve essere decifrata prima di sapere esattamente quale attività ha questo oggetto nei test. Inoltre, andare avanti e indietro per capire di cosa sono fatti esattamente e quali relazioni hanno attraverso le associazioni può essere un dolore che richiede tempo. 

La chiarezza di questi dettagli nella configurazione del test di solito aiuta molto a dire agli altri sviluppatori tutto ciò di cui hanno bisogno per lavorare con ogni particolare della tua suite di test, non dimenticare il tuo futuro io! In un mondo in cui non devi mai rivedere particolari test e nemmeno mai refactoring delle parti della tua suite di test, questo potrebbe non avere importanza, ma questo è un vero sogno per ora!

Vogliamo avere meno collaboratori e meno dati possibili per ogni test. permettere lavora contro di te anche su questo fronte. Questi dispositivi consentono di accumulare molti attributi e metodi che li rendono troppo grandi. 

Se inizi a scendere lungo la strada, spesso finirai con oggetti piuttosto grassi che cercano di rendere felici molti test allo stesso tempo. Certo, puoi creare molte varianti di questi permettere cosa, ma questo rende l'idea di loro un po 'irrilevante, penso. Perché non fare un passo in più, evitarlo e affidarsi a Ruby senza la magia RSPec DSL?

Sono più nel campo di stare dalla parte del codice di installazione ripetuto per ogni test che essere eccessivamente ASCIUTTO, oscuro o criptico nella mia suite di test. Cercherò sempre più leggibilità. Il metodo di prova dovrebbe chiarire la causa e l'effetto delle parti coinvolte: l'utilizzo di collaboratori di oggetti che potrebbero essere definiti lontano dall'esercizio di test non è nel vostro interesse. Se hai bisogno di estrarre materiale, usa metodi espressivi che racchiudono questa conoscenza. 

Queste sono praticamente sempre una scommessa sicura. In questo modo è anche possibile fornire l'impostazione effettivamente necessaria per ciascun test e non causare test lenti perché sono coinvolti dati non necessari. Buone vecchie variabili, metodi e classi sono spesso tutto ciò che serve per fornire test più veloci e stabili che siano più facili da leggere. 

Ospiti misteriosi

I Mystery Guests sono RSpec DSL Puzzles, davvero. Per un po ', i vari oggetti definiti tramite RSpec DSL permettere non è difficile da tenere a bada, ma presto, quando la suite di test cresce, inviti un sacco di ospiti misteriosi nelle tue specifiche. Questo dà al tuo sé futuro e ad altri inutili puzzle contestuali da risolvere. 

Il risultato saranno test oscuri che richiedono di entrare nella modalità completa di Sherlock Holmes. Immagino che suoni molto più divertente di quello che è. In conclusione, è uno spreco di tempo per tutti.

Gli ospiti del mistero pongono due domande problematiche:

  • Da dove viene questo oggetto??
  • Di cosa è composto esattamente?
descrivi Mission do let (: agent_01) build_stubbed (: agent, nome: 'James Bond', numero: '007') let (: agent_02) build_stubbed (: agente, nome: 'Moneypenny', numero: '243' ) let (: title) 'Moonraker' let (: mission) build_stubbed (: mission, title: title) mission.agents << agent_01 << agent_02… #lots of other tests describe '#top_agent' do it 'returns highest ranking agent associated to a mission' do expect(mission.top_agent).to eq('James Bond') end end end

Questo descrive il blocco per #top_agent manca di chiarezza e contesto. Quale agente è coinvolto e di quale missione stiamo parlando qui? Ciò costringe gli sviluppatori a cercare oggetti che all'improvviso compaiono nei test. 

Esempio classico di un ospite misterioso. Quando abbiamo un sacco di codice tra il test pertinente e l'origine di questi oggetti, aumenti le possibilità di oscurare quello che sta succedendo nei nostri test.

La soluzione è abbastanza semplice: hai bisogno di nuove "fixture" e costruisci versioni locali degli oggetti con esattamente i dati di cui hai bisogno, e non di più! Factory Girl è una buona scelta per gestirlo. 

Questo approccio può essere considerato più prolisso e talvolta potresti duplicare materiale, estrarre elementi in un metodo è spesso una buona idea, ma è molto più espressivo e mantiene i test focalizzati fornendo al contempo un contesto.

descrivi Mission do # ... # ... # ... #lots di altri test descrivi '#top_agent' do it 'restituisce un elenco di tutti gli agenti associati a una missione' do agent_01 = build_stubbed (: agent, name: 'James Bond', numero ' 007 ') agent_02 = build_stubbed (: agente, nome:' Moneypenny ', numero' 243 ') mission = build_stubbed (: missione, titolo:' Moonraker ') mission.agents << agent_01 << agent_02 expect(mission.top_agent).to eq('James Bond') end end end

L'esempio precedente crea tutti gli oggetti necessari per i nostri test nel caso di test effettivo e fornisce tutto il contesto desiderato. Lo sviluppatore può rimanere concentrato su un particolare caso di test e non ha bisogno di "scaricare" un altro caso, forse totalmente non correlato, per affrontare la situazione. Niente più oscurità!

Sì, hai ragione, questo approccio significa che non stiamo raggiungendo il livello più basso di duplicazione possibile, ma la chiarezza in questi casi è molto più importante per la qualità della tua suite di test e quindi per la robustezza del tuo progetto. La velocità con cui è possibile applicare in modo efficace le modifiche ai test svolge anche un ruolo in tal senso. 

Un altro aspetto importante del test è che la tua suite di test non solo può funzionare come documentazione, ma assolutamente dovrebbe! La duplicazione zero non è un obiettivo che ha un effetto positivo per le specifiche che documentano la tua app. Mantenere la duplicazione inutile sotto controllo è comunque un obiettivo importante per mantenere l'equilibrio visivo qui!  

Test oscuri

Di seguito è riportato un altro esempio che tenta di impostare tutto ciò che è necessario localmente nel test, ma non riesce anche perché non ci sta raccontando la storia completa.

... contesto "stato agente" fallo "restituisce lo stato dell'agente della missione" do double_o_seven = build_stubbed (: agent) mission = build_stubbed (: mission, agent: double_o_seven) expect (mission.agent_status) .to eq (double_o_seven.status) fine fine

Stiamo creando un agente generico. Come facciamo a sapere che è 007? Stiamo anche testando lo stato dell'agente, ma non si trova nemmeno da nessuna parte, né nel setup né esplicitamente durante la fase di verifica nel nostro aspettarsi dichiarazione. La relazione tra il double_o_seven.status e lo stato della missione potrebbe essere confuso dal momento che sta venendo fuori dal nulla in realtà. Possiamo fare meglio:

... contesto "stato agente" fallo "restituisce lo stato dell'agente della missione" fai double_o_seven = build_stubbed (: agente, nome: "James Bond", stato: "Manca in azione")) mission = build_stubbed (: mission, agent: double_o_seven) expect (mission.agent_status) .to eq ('James Bond: Missing in action') end end

Ancora una volta, qui abbiamo tutto ciò di cui abbiamo bisogno per raccontare una storia. Tutti i dati di cui abbiamo bisogno sono proprio di fronte a noi.

Test lenti

Quindi, hai iniziato a entrare in Test-Driven-Development, e hai iniziato ad apprezzare ciò che offre. Complimenti, è fantastico! Sono sicuro che né la decisione di farlo né la curva di apprendimento per arrivarci sono stati esattamente un gioco da ragazzi. Ma quello che succede spesso dopo questo primo passo è che cerchi di avere una copertura completa del test e inizi a capire che qualcosa non funziona quando la velocità delle tue specifiche inizia a infastidirti. 

Perché la tua suite di test sta diventando sempre più lenta, anche se pensi di fare tutte le cose giuste? Ti senti un po 'punito per aver scritto dei test? I test lenti fanno schifo! Ci sono un paio di problemi con loro. Il problema più importante è che i test lenti portano a saltare i test a lungo termine. Una volta che ti trovi in ​​un punto in cui la tua suite di test impiegherà un'eternità per finire, sarai molto più disposto a pensare a te stesso: "Avvitali, li eseguirò più tardi! Ho cose migliori da fare che aspettare che queste cose finiscano. "E hai assolutamente ragione, hai cose migliori da fare.

Il problema è che i test lenti sono più propensi ad accettare compromessi sulla qualità del tuo codice di quanto possa sembrare ovvio all'inizio. I test lenti alimentano anche le argomentazioni della gente contro TDD, in modo ingiusto quindi, penso. Non voglio nemmeno sapere cosa hanno da dire i product manager non tecnici se devi regolarmente uscire per una bella pausa caffè solo per eseguire la tua suite di test prima di poter continuare il tuo lavoro.

Non andiamo su quella strada! Quando hai solo bisogno di un po 'di tempo per esercitare i tuoi test e di conseguenza ottenere cicli di feedback super rapidi per sviluppare ogni fase di nuove funzionalità, praticare TDD diventa molto più attraente e meno un argomento. Con un po 'di lavoro e attenzione lungo il percorso, possiamo evitare i test slow-motion in modo abbastanza efficace. 

I test lenti sono anche un killer per entrare nella "zona". Se vieni tolto dal flusso spesso nel tuo processo, la qualità del tuo lavoro complessivo potrebbe anche risentire di dover aspettare che i test lenti tornino da un costoso viaggio di andata e ritorno. Volete ottenere il maggior numero possibile di "tempo nella zona" - i test insopportabilmente lenti sono i principali distruttori di flusso.

Un altro problema che vale la pena menzionare in questo contesto è che questo potrebbe portare a test che coprono il codice, ma poiché non ci vorrà del tempo per finire di esercitare l'intera suite, o scrivere test dopo il fatto, il design delle tue app non sarà guidato da test più. Se non sei sul treno hype Test-Driven, questo potrebbe non infastidirti molto, ma per le persone di TDD, quell'aspetto è essenziale e non dovrebbe essere trascurato. 

In conclusione, più velocemente i test, più sarai disposto a esercitarli, che è il modo migliore di progettare app e di individuare i bug in anticipo e spesso. 

Cosa possiamo fare per accelerare i test? Ci sono due velocità che sono importanti qui:

  • la velocità con cui i test possono realmente eseguire la tua suite
  • la velocità per ottenere feedback dalla tua suite di test per progettare la tua app

Evita di scrivere nel database quanto più puoi

Ciò non significa che dovresti evitare tutti i costi. Spesso non è necessario scrivere test che esercitano il database e si può ritagliare un sacco di tempo che i test devono eseguire. Usando solo nuovo istanziare un oggetto è spesso sufficiente per le impostazioni di prova. Faking fuori oggetti che non sono direttamente sotto test è un'altra opzione praticabile. 

Creare duplicati di test è un buon modo per rendere più veloci i test mantenendo gli oggetti collaborativi di cui hai bisogno per la tua configurazione super focalizzata e leggera. Factory Girl offre anche varie opzioni per "creare" i dati di test in modo intelligente. Ma a volte non c'è modo di salvare il database (che è molto meno spesso di quanto ci si potrebbe aspettare), e questo è esattamente dove si dovrebbe tracciare la linea. In qualsiasi altro momento, evitatelo come un inferno e la vostra suite di test rimarrà veloce e agile. 

A tale proposito, dovresti anche mirare a una quantità minima di dipendenze, il che significa che la quantità minima di oggetti che hai bisogno di collaborare per far passare i tuoi test, pur risparmiando il meno possibile il database lungo la strada. L'eliminazione degli oggetti, che sono semplici collaboratori e non direttamente sotto test, spesso rende anche la configurazione più facile da digerire e più semplice da creare. Un bel miglioramento della velocità in generale con uno sforzo minimo.

Costruisci i tuoi test con la piramide dei test in mente

Ciò significa che si desidera avere una maggioranza di test unitari in fondo a questa gerarchia, che si concentrano tutti su parti molto specifiche della propria applicazione in isolamento e il più piccolo numero di test di integrazione nella parte superiore di questa piramide. I test di integrazione simulano un utente che attraversa il tuo sistema mentre interagisce con un gruppo di componenti che vengono esercitati nello stesso periodo. 

Sono facili da scrivere ma non così facili da mantenere, e le perdite di velocità non valgono la pena di percorrere la via facile. I test di integrazione sono praticamente l'opposto dei test unitari per quanto riguarda l'alto livello e l'assorbimento di molti componenti che è necessario impostare nei test, il che è uno dei motivi principali per cui sono più lenti dei test unitari. 

Immagino che questo chiarisca perché dovrebbero essere in cima alla tua piramide di test per evitare perdite di velocità significative. Un altro aspetto importante qui è che si desidera avere una sovrapposizione minima tra queste due categorie di test - idealmente si desidera testare le cose solo una volta, dopo tutto. Non puoi aspettarti una separazione perfetta, ma cercare il meno possibile è un obiettivo ragionevole e realizzabile.

Contrariamente ai test unitari, si desidera testare il minor numero possibile di dettagli con i test di integrazione. La meccanica interna dovrebbe già essere coperta da ampi test unitari. Concentrati invece solo sulle parti più essenziali che le interazioni devono essere in grado di esercitare! L'altro motivo principale è che un webdriver deve simulare il passaggio attraverso un browser e l'interazione con una pagina. Questo approccio non elimina nulla o molto poco, salva le informazioni nel database e passa davvero attraverso l'interfaccia utente. 

Questo è anche uno dei motivi per cui possono essere chiamati test di accettazione perché questi test cercano di simulare un'esperienza utente reale. Questo è un altro importante rallentamento che vuoi esercitare il meno possibile. Se hai un sacco di questi test, suppongo più del 10% dal tuo numero totale di test, dovresti rallentare e ridurre quel numero al minimo possibile. 

Inoltre, tieni presente che a volte non hai bisogno di esercitare l'intera app: un test di visualizzazione più piccolo e mirato spesso fa anche il trucco. Sarai molto più veloce se riscrivi un paio dei tuoi test di integrazione che testano solo un po 'di logica che non richiede un controllo completo dell'integrazione. Ma non fatevi scriverne nemmeno una tonnellata; offrono il minimo bang per il dollaro. Detto questo, i test di integrazione sono fondamentali per la qualità della tua suite di test, e devi trovare un equilibrio tra l'essere troppo avaro applicandoli e non averne troppi in giro.

Ottenere velocemente feedback dalla tua app e dai test

Feedback rapidi e cicli di iterazione rapidi sono la chiave per progettare i tuoi oggetti. Una volta che inizi a evitare di eseguire questi test frequentemente, stai perdendo questo vantaggio, che è un grande aiuto per la progettazione di oggetti. Non aspettare fino a quando il tuo servizio di Continuous Integration scelto non inizia a testare la tua intera applicazione. 

Allora, qual è un numero magico che dovremmo tenere a mente durante l'esecuzione dei test? Bene, persone diverse ti diranno diversi punti di riferimento per questo. Penso che rimanere sotto i 30 secondi sia un numero molto ragionevole che rende molto probabile l'esecuzione di un test completo su base regolare. Se lasci questo benchmark sempre più indietro, alcuni refactoring potrebbero essere in ordine. Ne varrà la pena e ti farà sentire molto più a tuo agio perché puoi effettuare il check-in più regolarmente. Molto probabilmente andrai molto più veloce anche in avanti.

Vuoi che la finestra di dialogo con i tuoi test sia il più veloce possibile. Stringere questo ciclo di feedback usando un editor che possa anche esercitare i test non deve essere sottovalutato. Passare avanti e indietro tra l'editor e il terminale non la migliore soluzione per gestire questo. Questo diventa vecchio molto rapidamente. 

Se ti piace usare Vim, hai un motivo in più per investire un po 'di tempo nel diventare più efficiente nell'usare il tuo editor. Ci sono molti strumenti a portata di mano disponibili per i peeps di Vim. Ricordo che Sublime Text offre anche di eseguire test dall'interno dell'editor, ma a parte questo, devi fare un po 'di ricerca per scoprire quale sia il tuo editor di scelta in grado di fare al riguardo. L'argomento che ascolterai spesso dagli appassionati di TDD è che non vuoi lasciare il tuo editore perché nel complesso passerai troppo tempo a farlo. Vuoi rimanere molto di più nella zona e non perdere il filo del pensiero quando puoi fare questo genere di cose tramite una scorciatoia veloce all'interno del tuo editor di codice. 

Un'altra cosa da notare è che vuoi anche essere in grado di suddividere i test che vuoi eseguire. Se non è necessario eseguire l'intero file, è consigliabile eseguire un singolo test o un blocco incentrato solo su ciò di cui si ha bisogno per ottenere un feedback al momento. Avere scorciatoie che ti aiutano a eseguire test singoli, singoli file o solo l'ultimo test ti fa risparmiare un sacco di tempo e ti tiene nella zona, per non parlare dell'elevato livello di praticità e di sentirti anche molto cool. È incredibile quanto a volte possano essere incredibili strumenti di codifica.

Un'ultima cosa per la strada. Usa un preloader come Spring. Sarai sorpreso di quanto tempo puoi radere quando non devi caricare Rails per ogni prova. La tua app verrà eseguita in background e non è necessario eseguire l'avvio in qualsiasi momento. Fallo!

infissi

Non sono sicuro che i dispositivi siano ancora un problema per i neofiti che arrivano in terra Ruby / Rails. Nel caso in cui nessuno ti abbia dato istruzioni su di loro, proverò a farti accelerare in un batter d'occhio su queste temute cose. 

I dispositivi di database ActiveRecord sono ottimi esempi di avere tonnellate di Mystery Guest nella tua suite di test. Agli albori di Rails e Ruby TDD, i dispositivi YAML erano di fatto lo standard per la configurazione dei dati di test nella vostra applicazione. Hanno svolto un ruolo importante e hanno contribuito a far progredire l'industria. Al giorno d'oggi, hanno una replica abbastanza cattiva.

Calendario YAML

Quartiermastro: nome: Q preferito_gadget: Skill radio: inventando aggeggi e hacking 00Agent: nome: James Bond favorite_gadget: sottomarino Lotus Esprit abilità: ottenere Bond Girls uccise e infiltrazioni segrete

La struttura tipo hash sembra davvero maneggevole e facile da usare. Puoi anche fare riferimento ad altri nodi se vuoi simulare le associazioni dei tuoi modelli. Ma è lì che la musica si ferma e molti dicono che inizia il loro dolore. Per i set di dati che sono un po 'più coinvolti, i dispositivi YAML sono difficili da mantenere e difficili da modificare senza influenzare altri test. Voglio dire, puoi farli funzionare, naturalmente - dopotutto, gli sviluppatori li hanno usati in abbondanza in passato - ma un sacco di sviluppatori concordano sul fatto che il prezzo da pagare per la gestione degli infissi è solo un po 'avaro.

Uno scenario che vogliamo assolutamente evitare è quello di modificare piccoli dettagli su un dispositivo esistente e causare il fallimento di tonnellate di test. Se questi test fallimentari non sono collegati, la situazione è ancora peggiore: un buon esempio di test troppo fragili. Al fine di "proteggere" i test esistenti da questo scenario, questo può anche portare a far crescere il set di attrezzature oltre ogni ragionevole dimensione - essendo ASCIUTATO con i proiettori molto probabilmente non sul tavolo più a quel punto. 

Per evitare di rompere i dati del test quando si verificano inevitabili cambiamenti, gli sviluppatori sono stati felici di adottare nuove strategie che offrivano maggiore flessibilità e comportamento dinamico. È qui che Factory Girl è arrivata e ha baciato i giorni della YAML addio. 

Un altro problema è la forte dipendenza tra il test e il file .yml. Poiché i dispositivi sono definiti in un file .yml separato, gli ospiti misteriosi sono anche un grande dolore in attesa di morderti a causa dell'oscurità. Ho già detto che i dispositivi sono stati importati nel database di test senza eseguire convalide e non aderiscono al ciclo di vita di Active Record? Sì, non è nemmeno fantastico, da qualunque angolo tu voglia guardarlo! 

Factory Girl ti consente di evitare tutto ciò creando oggetti pertinenti ai test in linea e solo con i dati necessari per quel caso specifico. Il motto è, definisci solo il minimo indispensabile nelle tue definizioni di fabbrica e aggiungi il resto su una base test-by-test. A livello locale (nei tuoi test) i valori predefiniti di override definiti nelle tue fabbriche sono un approccio molto migliore rispetto ad avere tonnellate di unicorni di dispositivi in ​​attesa di essere superati in un file di fixture. 

Questo approccio è anche più scalabile. Factory Girl ti offre molti strumenti per creare tutti i dati di cui hai bisogno, con tutte le sfumature che desideri, ma ti fornisce anche tonnellate di munizioni per rimanere SECCO dove necessario. I pro ei contro sono ben bilanciati con questa libreria, penso. Non trattare più con convalide non è più motivo di preoccupazione. Penso che l'uso del modello di fabbrica per i dati di test sia più che ragionevole ed è uno dei motivi principali per cui Factory Girl è stata così ben accolta dalla community. 

La complessità è un nemico in rapida crescita che i dispositivi YAML non sono in grado di affrontare efficacemente. In qualche modo, penso ai dispositivi come permettere con steroidi. Non li stai solo mettendo ancora più lontano - essendo in un file separato e tutto - puoi anche precaricare potenzialmente più dispositivi di quanti ne potrebbero effettivamente avere bisogno. RIPOSA IN PACE!

Test fragili

Se le modifiche alle specifiche portano a errori apparentemente non correlati in altri test, probabilmente stai osservando una suite di test che è diventata fragile a causa delle cause sopra menzionate. Questi test infestati da rompicapo, spesso intriganti, portano facilmente a una casa di carte instabile. 

Quando gli oggetti necessari per i test sono definiti "molto lontani" dallo scenario di test effettivo, non è difficile trascurare le relazioni che questi oggetti hanno con i loro test. Quando il codice viene cancellato, regolato o semplicemente l'oggetto di setup in questione viene accidentalmente ignorato, inconsapevole di come questo potrebbe influenzare altri test in giro, i test falliti non sono un incontro raro. Appaiono facilmente come fallimenti totalmente indipendenti. Penso che sia giusto includere tali scenari nella categoria del codice strettamente accoppiato.

descrivi Mission do let (: agent) build_stubbed (: agent, name: 'James Bond', numero: '007') let (: title) 'Moonraker' let (: mission) build_stubbed (: missione, titolo : titolo) # ... # ... # ... #lotti di altri test descrivono '#joint_operation_agent_name' do let (: agent) build_stubbed (: agente, nome: 'Felix Leiter', agenzia: 'CIA') mission.agents << agent it “returns mission's joint operation's agent name” do expect(mission.joint_operation_agent_name).to eq('Felix Leiter') end end end

In questo scenario, abbiamo chiaramente modificato localmente lo stato di un oggetto che è stato definito nel nostro setup. Il agente in questione è ora un agente della CIA e ha un nome diverso. missione viene di nuovo fuori dal nulla. Roba brutta, davvero. 

Non è una sorpresa quando altri test che si basano su una versione diversa di agente iniziare a saltare in aria. Liberiamoci di permettere sciocchezze e costruire gli oggetti di cui abbiamo bisogno di nuovo proprio dove li testiamo - con solo gli attributi di cui abbiamo bisogno per il test case, ovviamente. 

descrivi Mission do # ... # ... # ... #lots di altri test descrivi '#joint_operation_agent_name' do agent = build_stubbed (: agent, nome: 'Felix Leiter', agenzia: 'CIA') mission = build_stubbed (: mission) mission.agents << agent it “returns mission's joint operation's agent name” do expect(mission.joint_operation_agent_name).to eq('Felix Leiter') end end end

È importante capire come gli oggetti sono correlati, idealmente con la quantità minima di codice di configurazione. Non vuoi mandare altri sviluppatori a caccia di selvaggina per capire come stanno queste cose quando inciampano nel tuo codice. 

Se è molto difficile riuscire a cogliere velocemente e una nuova funzionalità deve essere implementata ieri, questi puzzle non possono aspettarsi di ricevere la massima priorità. Questo a sua volta spesso significa che le nuove cose vengono sviluppate in cima a quel contesto poco chiaro, che è una base fragile per andare avanti e anche invitare super per bug in fondo alla strada. La lezione da portare via qui non è quella di scavalcare la roba laddove possibile.

Attributi dei dati

Un ultimo consiglio utile per evitare test fragili è usare gli attributi dei dati nei tag HTML. Fatti un favore e usali - puoi ringraziarmi più tardi. Ciò consente di separare gli elementi necessari da testare dalle informazioni sullo stile che i tuoi designer potrebbero toccare frequentemente senza il tuo coinvolgimento. 

Se si codifica una classe come Class = 'mission-wrapper' nel tuo test e uno stilista intelligente decide di cambiare questo nome scadente, il test verrà influenzato inutilmente. E il progettista non è da incolpare, ovviamente. Come diavolo saprebbe che ciò influisce su parte della tua suite di test, molto improbabile, almeno. 

 

<% = @mission.agent_status %>

...
 contesto "stato dell'agente della missione" fallo "fa qualcosa con una missione" fai ... aspetto (pagina). per avere_css '[data-role = single-mission]' end end

Ci aspettiamo di vedere alcuni elementi HTML su una pagina e contrassegnati con a Dati-ruolo. I progettisti non hanno motivo di toccarlo, e tu sei protetto contro i test fragili che accadono a causa di cambiamenti sul lato stilistico delle cose. 

È una strategia piuttosto efficace e utile che sostanzialmente non ti costa nulla in cambio. L'unica cosa che potrebbe essere necessaria è avere una breve conversazione con i designer. Pezzo di torta!

Pensieri finali

Vogliamo evitare di distrarre le persone che leggeranno i nostri test o, peggio ancora, li confonderanno. Questo sta aprendo la porta ai bug ma può anche essere costoso perché può costare tempo prezioso e potere del cervello. Quando crei i tuoi test, cerca di non ignorare le cose: non aiuta a creare chiarezza. Più probabilmente questo porterà a bug sottili e dispendiosi in termini di tempo e non influenzerà l'aspetto della documentazione del tuo codice in modo positivo. 

Questo crea un onere inutile che possiamo evitare. Cambiare i dati dei test più del necessario è anche un po 'paranoico. Mantieni il più semplice possibile! Questo ti aiuta davvero a evitare l'invio di altri sviluppatori o il tuo futuro se stessi su inseguimenti di selvaggina d'oca. 

C'è ancora molto da imparare su cose che dovresti evitare durante i test, ma credo che questo sia un buon inizio. Gente che è piuttosto nuova a tutte le cose TDD dovrebbe essere in grado di gestire questi pochi AntiPattern subito prima di tuffarsi in acque più avanzate.