E 'anti-pattern mescolare test di unità e test web? [duplicare]

1

È una domanda indipendente dal linguaggio, ad es. Ho un test unitario come

# Unit test
User user = User.create('john');
assertEquals("User name is john", "john", user.getName());

# Web test start from here
goTo("/user/john");
assertTitleEquals("john");

Pensi che sia un anti-modello? Sebbene io possa scrivere una suite completa per il test del selenio per fare la stessa cosa, ma usando il codice sopra, risparmi molto tempo (ad esempio, non più clic ("Login"), waitUntil ecc., E non devo preoccuparmi se la mia interfaccia utente è cambiato, sembra un approccio rapido e più stabile per testare?

    
posta user34401 28.08.2014 - 20:04
fonte

3 risposte

3

Sì, questo è un anti-modello. "I test unitari dovrebbero avere solo una ragione per fallire." è una best practice comune e ben nota. Questo test può fallire per due motivi.

E ti avverto di non risparmiare un po 'di tempo ora (condensando i test) per pagarlo in un secondo momento trascorrendo un sacco di tempo rintracciando l'accoppiamento nel test o l'ambiguità nei test falliti.

    
risposta data 28.08.2014 - 20:12
fonte
3

Questo non è un test unitario; è un test di accettazione. Penso che alcune persone siano appese al fatto che tu l'abbia definito un test unitario senza guardare a quello che stai effettivamente cercando di ottenere.

Sembra che ciò che stai facendo nella prima serie di passaggi stia usando un codice perfettamente decente che proviene da un framework di test delle unità per impostare un contesto. Cioè, qualcosa del tipo:

Given John is registered as a user

Se stavi facendo BDD, o usando un framework BDD, questo sarebbe il tuo passo. Non importa come è stato impostato il contesto, perché quello che ci interessa veramente è il risultato:

Then John's title should be "John".

Questo dovrebbe essere vero indipendentemente da come è stato creato il contesto. La creazione del contesto colpendo il database o utilizzando un servizio o qualsiasi altro meccanismo è OK. Se senti la necessità di verificare che le pagine di creazione dell'utente funzionino correttamente, trasformale in uno scenario separato (o test).

Il tuo test va quindi bene, perché quello che stai facendo è un test a livello di sistema (o test di accettazione se vuoi), non un test di unità (anche se stai usando il codice di test unitario al suo interno).

L'affermazione che la registrazione di John esiste potrebbe essere ridondante, ma è utile se si desidera verificare che il contesto sia stato impostato correttamente (ad esempio, il database non è fuori sincrono con quella chiamata User.create ) senza dover aspettare che i prossimi passi del test falliscano.

Potresti anche voler mettere alcune astrazioni attorno ai passaggi, solo per mantenerli mantenibili. È possibile utilizzare i framework BDD in lingua inglese o, più in modo sostenibile, creare un bello piccola DSL come questa . Vale anche la pena dare un'occhiata al modello oggetto pagina . Ciò manterrà la tua impostazione del contesto pulita e renderà molto più facile cambiarla in seguito se decidi di fare qualcosa di diverso.

L'equivalente del test unitario "l'unico motivo per fallire" nei test a livello di sistema è "solo un aspetto del comportamento", che è la stessa cosa, solo a un livello più alto di astrazione.

Non dimenticare che il TDD di livello di classe è anche molto prezioso!

    
risposta data 31.08.2014 - 14:02
fonte
2

Quante impalcature richiedono i test dell'interfaccia Selenium o quanto tempo ci vuole per eseguirle sono fattori pratici. È possibile segmentare razionalmente tali test in una suite "beyond unit test". Basta non eliminare quella fase di test "perché non è un test unitario". Se stai lavorando per la qualità del software, non puoi essere "salvato dal campanello" di ciò che rende un puro test unitario o meno.

Una risposta tradizionale sarebbe: Beh, è necessario aggiungere altri livelli di test (modulo, integrazione, specifica, accettazione, ...) e testare anche queste cose - ma questo è al di fuori dello scopo del puro test delle unità. Ma questa distinzione è spesso usata per puntare su quelle altre forme di test o lasciarla a qualcun altro. "Non è il mio lavoro, amico, sono solo responsabile dei test delle unità, qualcun altro è responsabile dell'integrazione e dei test dell'interfaccia utente." Quel punting è un'abdicazione di responsabilità, e ostile alla filosofia di TDD di integrare la codifica e il testing. È anche un grande motivo per cui i test unitari sono infami per il passaggio a pieni voti, anche quando il il codice nel suo insieme si sta ancora rompendo o non sta facendo il lavoro che è stato progettato per fare .

C'è un posto per segmentare i reami di test. Test delle prestazioni, test di walk-through-the-UI, test di intrusione e test di conformità esaurienti contro tutte le possibili librerie e piattaforme supportate possono richiedere un considerevole middleware e istanze virtuali e potrebbero richiedere dekaminutes o ore per il completamento. Esegui occasionalmente queste suite di test piuttosto che ogni modifica del codice. Ma per carità, non usare la loro natura "di livello superiore" per evitare di farle.

Spesso c'è anche l'idea che l'integrazione, l'interfaccia utente e altre forme di test richiedano strumenti diversi. Mentre potrebbe essere necessario qualche strumento aggiuntivo (Selenium, in questo caso), ma non riesco a vedere il punto nel richiedere una base di test completamente diversa di test runner, fixture, librerie di supporto e di derisione e così via. Direi che avere un'infrastruttura diversa per 4 o 5 livelli di test desiderati è anti-semplicità e in definitiva un anti-modello.

La mia esperienza è che la rigida conformità al dogma dei test unitari - "solo una possibile ragione per fallire" e "non testare le cose insieme", ad esempio - è restrittiva e in definitiva controproducente. Sicuramente vuoi test per esercitare il tuo codice in modo chiaro, semplice e diretto. I pur unit test possono e aiutano a farlo. Ma perché fermarsi qui?

Costruisco test di "unità" con un modello espanso di ciò che costituisce un'unità - non solo singoli atomi o particelle , ma più routine e oggetti, che agiscono insieme . Atomi composti in molecole e quindi molecole composte in molecole più grandi.

Rilassare la nozione di ciò che costituisce una "unità" e l'infrastruttura di collaudo delle unità di misura per l'integrazione e i test dell'interfaccia utente potrebbero non farmi vincere premi per testare la purezza, ma aiuta i requisiti più grandi. Ottiene più test scritti ed eseguiti - sia in senso assoluto, sia per ora di test. E ottiene una parte più ampia del mio codice testato, in modi che imitano l'uso reale.

Non è questo l'obiettivo finale? Avere prodotti software di qualità più robusti, testati insieme? In tal caso, andare avanti e utilizzare un modello di test unitario puro, senza dipendenze, qualunque per iniziare. Non fermarti qui. Quel test di livello leggermente superiore o visto da un utente potrebbe fallire in vari modi, o avere delle dipendenze - questo potrebbe essere un motivo per mettere quei test in differenti specifiche / file di test, o per eseguirli meno frequentemente. Ma non è un motivo per saltarli - e spesso, nemmeno una ragione per separarli dal processo di codifica di base.

    
risposta data 29.08.2014 - 01:17
fonte