Domanda

Quando inizialmente mi è stato presentato Mocks, sentivo che lo scopo principale era quello di simulare oggetti che provengono da fonti di dati esterne.In questo modo non dovevo mantenere un database di test unit test automatizzato, potevo semplicemente falsificarlo.

Ma ora comincio a pensarci diversamente.Mi chiedo se i Mock siano più efficaci per isolare completamente il metodo testato da qualsiasi cosa al di fuori di se stesso.L'immagine che continua a venire in mente è lo sfondo che usi quando dipingi.Vuoi evitare che la vernice si sparga su tutto.Sto solo testando quel metodo e voglio solo sapere come reagisce a questi fattori esterni falsificati?

Sembra incredibilmente noioso farlo in questo modo, ma il vantaggio che vedo è che quando il test fallisce è perché è incasinato e non a 16 strati.Ma ora devo effettuare 16 test per ottenere la stessa copertura perché ogni pezzo verrebbe testato isolatamente.Inoltre ogni test diventa più complicato e più profondamente legato al metodo che sta testando.

Mi sembra giusto ma sembra anche brutale, quindi voglio sapere cosa pensano gli altri.

È stato utile?

Soluzione

Ti consiglio di dare un'occhiata all'articolo di Martin Fowler I mock non sono stub per un trattamento di Mocks più autorevole di quello che posso darti.

Lo scopo dei mock è quello di testare l'unità del codice isolando le dipendenze in modo da poter veramente testare un pezzo di codice a livello di "unità".Il codice in prova è il vero affare e ogni altro pezzo di codice su cui fa affidamento (tramite parametri o iniezione di dipendenze, ecc.) è un "Mock" (un'implementazione vuota che restituisce sempre i valori attesi quando viene chiamato uno dei suoi metodi).

All'inizio i mock possono sembrare noiosi, ma rendono gli unit test molto più semplici e robusti una volta che si impara a usarli.La maggior parte dei linguaggi dispone di librerie Mock che rendono il mocking relativamente banale.Se utilizzi Java, ti consiglio il mio preferito: EasyMock.

Concludo con questo pensiero:sono necessari anche test di integrazione, ma avere un buon volume di unit test ti aiuta a scoprire quale componente contiene un bug, quando ne esiste uno.

Altri suggerimenti

Non percorrere il sentiero oscuro, Maestro Luke.:) Non prendere in giro tutto.Potresti ma non dovresti...Ecco perché.

  • Se continui a testare ciascun metodo isolatamente, avrai delle sorprese e del lavoro da fare quando li riunirai tutti insieme. BIG BANG.Costruiamo oggetti in modo che possano lavorare insieme per risolvere un problema più grande..Di per sé sono insignificanti.Voi bisogno di sapere se tutti i collaboratori stanno lavorando come previsto.
  • Scherzi rendere fragili i test introducendo la duplicazione - Sì, lo so, sembra allarmante.Per ogni simulazione prevista che imposti, ci sono n posti in cui esiste la firma del tuo metodo.Il codice effettivo e le tue finte aspettative (in più test).Cambiare il codice attuale è più semplice...aggiornare tutte le finte aspettative è noioso.
  • Tuo test è ora a conoscenza di informazioni privilegiate sull'implementazione.Quindi il tuo test dipende da come hai scelto di implementare la soluzione...Cattivo.I test dovrebbero essere una specifica indipendente che può essere soddisfatta da più soluzioni.Dovrei avere la libertà di premere semplicemente Elimina su un blocco di codice e reimplementare senza dover riscrivere la suite di test..perché i requisiti rimangono gli stessi.

Per concludere, dirò "Se starnazza come un'anatra, cammina come un'anatra, allora probabilmente è un'anatra" - Se ti sembra sbagliato...probabilmente lo è.*Utilizzare mock per astrarre i problemi secondari come operazioni di I/O, database, componenti di terze parti e simili.Come il sale, una parte è necessaria..troppo e :x *
Questa è la guerra santa tra test basati sullo stato e test basati sull'interazione.Cercare su Google ti darà una visione più approfondita.

Una precisazione:Sto incontrando una certa resistenza rispetto atest di integrazione qui :) Quindi, per chiarire la mia posizione..

  • I mock non figurano nell'ambito dei "Test di accettazione"/Integrazione.Li troverai solo nel mondo Unit Testing..e questo è il mio obiettivo qui.
  • I test di accettazione sono diversi e lo sono molto necessari, senza sminuirli.Ma i test unitari e i test di accettazione sono diversi e dovrebbero essere mantenuti diversi.
  • Non è necessario che tutti i collaboratori all'interno di un componente o pacchetto siano isolati gli uni dagli altri.Come la micro-ottimizzazione che è Overkill.Esistono per risolvere un problema insieme..coesione.

Si, sono d'accordo.Considero la derisione a volte dolorosa, ma spesso necessaria, affinché le tue prove diventino davvero unità test, cioèsolo l'unità più piccola su cui è possibile eseguire il test è in fase di test.Ciò consente di eliminare qualsiasi altro fattore che potrebbe potenzialmente influenzare l’esito del test.Alla fine ti ritroverai con molti più piccoli test, ma diventa molto più facile capire dove si trova un problema con il tuo codice.

La mia filosofia è che dovresti scrivere codice testabile per adattarsi ai test,
non scrivere test per adattarli al codice.

Per quanto riguarda la complessità, la mia opinione è che i test dovrebbero essere semplici da scrivere, semplicemente perché se lo sono si scrivono più test.

Potrei essere d'accordo sul fatto che potrebbe essere una buona idea se le classi che stai prendendo in giro non abbiano una suite di test, perché se avessero una suite di test adeguata, sapresti dove si trova il problema senza isolamento.

La maggior parte del tempo che ho utilizzato per gli oggetti fittizi è stato quando il codice per cui sto scrivendo i test è così strettamente accoppiato (leggi:cattiva progettazione), che devo scrivere oggetti fittizi quando le classi da cui dipendono non sono disponibili.Sicuramente ci sono usi validi per gli oggetti fittizi, ma se il tuo codice richiede il loro utilizzo, darei un'altra occhiata al design.

Sì, questo è lo svantaggio di testare con i mock.C'è molto lavoro da fare e sembra brutale.Ma questa è l'essenza del test unitario.Come puoi testare qualcosa in isolamento se non prendi in giro le risorse esterne?

D'altra parte, stai deridendo funzionalità lente (come database e operazioni di i/o).Se i test vengono eseguiti più velocemente, ciò renderà felici i programmatori.Non c'è niente di più doloroso che attendere test molto lenti, che impiegano più di 10 secondi per terminare l'esecuzione, mentre si tenta di implementare una funzionalità.

Se ogni sviluppatore del tuo progetto dedicasse del tempo a scrivere unit test, quei 16 livelli (di indiretto) non sarebbero un grosso problema.Spero che dovresti avere la copertura del test fin dall'inizio, giusto?:)

Inoltre, non dimenticare di scrivere un test di funzionalità/integrazione tra oggetti in collaborazione.Oppure potresti perderti qualcosa.Non sarà necessario eseguire spesso questi test, ma sono comunque importanti.

Su una scala, sì, i mock sono pensati per essere utilizzati per simulare fonti di dati esterne come un database o un servizio web.Su una scala più fine, tuttavia, se stai progettando un codice liberamente accoppiato, puoi tracciare linee in tutto il codice in modo quasi arbitrario su quello che potrebbe in qualsiasi momento essere un "sistema esterno".Prendi un progetto a cui sto lavorando attualmente:

Quando qualcuno tenta di effettuare il check-in, il CheckInUi invia un CheckInInfo opporsi ad a CheckInMediator oggetto che lo convalida utilizzando a CheckInValidator, quindi se è ok, riempie un oggetto di dominio denominato Transazione con CheckInInfo utilizzando CheckInInfoAdapter poi passa il Transazione a un'istanza di ITransactionDao.SaveTransaction() per persistenza.

In questo momento sto scrivendo alcuni automatizzati test di integrazione e ovviamente il CheckInUi E ITransactionDao sono finestre su sistemi esterni e sono quelli che dovrebbero essere derisi.Tuttavia, chi lo dirà ad un certo punto CheckInValidator non effettuerà una chiamata a un servizio Web?Ecco perché quando scrivi test unitari presumi che tutto ciò che non è la funzionalità specifica della tua classe sia un sistema esterno.Pertanto nel mio test unitario di CheckInMediator Prendo in giro tutti gli oggetti con cui parla.

MODIFICARE: Gishu è tecnicamente corretto, non tutto deve essere deriso, io ad esempio non prendo in giro CheckInInfo poiché è semplicemente un contenitore di dati.Tuttavia, tutto ciò che potresti vedere come un servizio esterno (ed è quasi tutto ciò che trasforma i dati o ha effetti collaterali) dovrebbe essere deriso.

Un'analogia che mi piace è pensare a un progetto correttamente accoppiato come a un campo con persone in piedi attorno a lui che giocano a palla.Quando a qualcuno viene passata la palla, potrebbe lanciarne una completamente diversa alla persona successiva, potrebbe anche lanciare più palline in successione a persone diverse o lanciare una palla e attendere di riceverla indietro prima di lanciarla a un'altra persona.È un gioco strano.

Ora, in qualità di allenatore e manager, ovviamente vorrai verificare come funziona la tua squadra nel suo insieme, quindi fai pratica di squadra (test di integrazione), ma chiedi anche a ogni giocatore di esercitarsi da solo contro i backstop e le macchine lanciapalle (test unitari con schernisce).L'unico pezzo che manca a questa immagine sono le finte aspettative e quindi abbiamo le nostre palle imbrattate di catrame nero in modo che macchino il backstop quando lo colpiscono.Ogni dispositivo di arresto ha una "area target" a cui la persona mira e se alla fine di una corsa di pratica non c'è alcun segno nero all'interno dell'area target, sai che qualcosa non va e che la persona ha bisogno di affinare la sua tecnica.

Prenditi davvero il tempo per impararlo correttamente, il giorno in cui ho capito Mocks è stato un grande momento a-ha.Combinalo con un'inversione del contenitore di controllo e non tornerò mai più indietro.

Nota a margine: uno dei nostri addetti IT è appena arrivato e mi ha regalato un laptop!

Come qualcuno ha detto prima, se prendi in giro tutto per isolare in modo più granulare rispetto alla classe che stai testando, rinunci a rafforzare la coesione nel codice che è in fase di test.

Tieni presente che la presa in giro ha un vantaggio fondamentale, la verifica del comportamento.Questo è qualcosa che gli stub non forniscono ed è l'altro motivo che rende il test più fragile (ma può migliorare la copertura del codice).

I mock sono stati inventati in parte per rispondi alla domanda:Come eseguiresti il ​​test unitario degli oggetti se non avessero getter o setter?

In questi giorni, consigliato la pratica è deridere i ruoli, non gli oggetti.Usa Mocks come strumento di progettazione per parlare di collaborazione e separazione delle responsabilità, e non come "stub intelligenti".

Gli oggetti mock sono 1) spesso usati come mezzo per isolare il codice sotto test, MA 2) come ha già sottolineato Keithb, sono importanti per "concentrarsi sulle relazioni tra oggetti che collaborano".Questo articolo fornisce alcuni approfondimenti e la storia relativa all'argomento: Progettazione guidata dalla responsabilità con oggetti simulati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top