Come testare un metodo che non è tanto un'unità, perché è più una classe di 'orchestrator' / 'process' / 'controller' / 'coordination' [duplicato]

4

Voglio testare un metodo che non è tanto un'unità, perché è più una classe di 'orchestrator' / 'process' / 'controller' / 'coordination'.

Questo è il caso:

Ho quattro classi testate da unità:

  • Uno è un servizio dati che può leggere / scrivere dati dal database
  • Il secondo è un servizio di scrittura che può creare contenuti per email / messaggi ecc.
  • Terzo è un servizio di posta che può inviare email
  • Quarto è un dat di classe in grado di creare compiti per gli utenti nel nostro sistema (le attività sono cose dovrebbero fare)

Ora ho creato una nuova classe, che invia un'email a tutte le persone in ritardo con il pagamento di una fattura. Legge i dati con il servizio dati, crea il testo appropriato con il servizio SMS, invia un'e-mail con il servizio di posta elettronica, scrive il nuovo stato della fattura con il servizio dati e crea un'attività quando l'e-mail per una specifica fattura non riesce.

Ora questa nuova classe è la mia classe "orchestrator" o "process" o "controller" o "coordination".

Ho questo tipo di classi molto nella nostra applicazione perché cerchiamo di rendere le nostre classi (come i dati / email / SMSservice) il più piccole possibile così quando 'il lavoro deve essere fatto', come in questo caso il ' invia tutte le persone in ritardo con il pagamento ", creiamo una nuova classe" orchestrator "o" process "o" controller "o" coordination ".

Penso di avere questo tipo di classi per la maggior parte delle mie azioni nei miei webcontrollers perché la maggior parte degli input inviati dal browser implica il coordinamento tra più classi (più piccole)

Ora come faccio a testare queste classi / metodi?

Ero solito prendere in giro tutte e 4 le classi nel mio test e verificare alla fine che le classi vengano chiamate e nel giusto ordine.

Ma sempre più leggo che non lo fai, perché poi provi per il funzionamento interno di un metodo, e quando rifattori quel metodo, il test fallisce. Quindi dovrei testare i risultati, non il lavoro interiore. Ma questo metodo è nullo, quindi non ci sono molti risultati da verificare. L'unica cosa che posso pensare ad esempio per verificare è: viene inviata una e-mail? Ma l'unico modo per verificare che è verificare il servizio di posta elettronica è chiamato, ma poi sono tornato a testare la parte interna.

Non vedo questo tipo di esempi nel test delle unità / libri tdd, perché la maggior parte delle volte funzionano solo con classi piccole come la classe calcolatrice, ma raramente vedo esempi per "orchestrator" classi come sto descrivendo, ma che si verificano molto nel mio codice.

Per coloro che pensano che sia un duplicato: penso che le risposte qui forniscano molto più background rispetto all'unica risposta all'altra domanda. A quell'altra domanda è stata data una risposta con un test di integrazione, e la mia domanda riguarda il test unitario, non i test di integrazione. Quindi non posso essere d'accordo con il segno di risposta doppio.

    
posta Michel 29.01.2015 - 09:22
fonte

4 risposte

15

Da ciò che descrivi direi che il modo in cui lo hai fatto - prendendo in giro i collaboratori - è l'approccio migliore. Può darsi che tu stia specificando troppo con la tua simulazione, ad esempio richiedendo un ordine che non è realmente richiesto dalle esigenze aziendali; se questo è il caso, potresti alleggerire i requisiti dell'ordine dei tuoi test. Ma fondamentalmente per il coordinatore vuoi sapere che:

  • dato un servizio dati che dice "queste persone sono in ritardo"
  • dato un servizio di testo che genera email del modulo "hey, sei in ritardo"
  • dato un servizio di posta elettronica che invia a un elenco di destinatari
  • invierà una richiesta al servizio di posta elettronica per inviare "hey, sei in ritardo" al suddetto gruppo di persone.

Se lo sta facendo (e alcune altre cose che hai menzionato che non mi sto preoccupando di specificare nuovamente qui), allora per quanto ti riguarda, la tua classe di coordinatore sta funzionando. È un test facile da scrivere con mock, pulito e comunicativo. Questo è il modo che consiglierei.

    
risposta data 29.01.2015 - 10:02
fonte
5

Non è assolutamente responsabilità del tuo coordinatore inviare posta, solo per chiedere che venga inviata. Ci sono molti motivi per cui una mail non può essere inviata o ritardata. È responsabilità della tua classe di posta elettronica

  1. invia posta valida
  2. rifiuta la posta non valida
  3. registra ciò che ha fatto (inclusi errori imprevisti nell'invio di posta valida)

Tutto ciò che il tuo coordinatore deve fare, per quanto riguarda la posta, è

  1. Richiedi la posta da inviare
  2. Reagisci appropriatamente se la chiamata all'oggetto di posta restituisce un errore.
  3. registra ciò che ha fatto

Se i test per la tua classe di posta sono completi, dovresti essere sicuro che verranno inviate richieste di posta valide e problemi registrati. Se, per qualche motivo, il tuo coordinatore può creare e-mail problematiche, ciò risulterà molto rapidamente in uso e avrai tutti i dati necessari dai log per risolvere il problema. Per favore sii rilassato su questo; non c'è modo di creare test che non garantiscano mai il fallimento. Accontentati di test che testano un contratto di componenti e che mostrano che la classe si comporta sempre responsabilmente sia quando una richiesta rispetta il contratto che quando lo interrompe.

È importante che i componenti siano testabili separatamente. Se testare un componente richiede che gli altri siano pienamente presenti, in realtà non sono componenti separati e rischi di creare una grossa palla di fango. In realtà è più pericoloso che deridere, perché rischi di creare dipendenze nascoste sui dettagli di implementazione di quegli altri componenti. Significa anche che eventuali modifiche interne a tali componenti impongono un aggiornamento al processo di generazione e test per questo. Quella squama terribilmente e fa perdere tempo a tutti.

Non importare alcuna logica dalla classe di posta nella simulazione. Si prega di fare test per il successo e l'insuccesso della classe mail, ma creare quegli eventi arbitrari, non qualcosa usando la logica copiata dalla classe reale nel proprio simulato. È una perdita di tempo e reintroduce il rischio di dipendenze nascoste nei dettagli di implementazione.

Costruisci il tuo sistema in base a questi principi. Fidati del sistema. Non complicarlo in un pasticcio perché vuoi dimostrare in ogni parte che l'intero sistema funziona. Ciò fallirà e renderà più probabile il fallimento.

tl; dr

La legge di Demeter si applica anche ai test.

    
risposta data 29.01.2015 - 14:10
fonte
3

Non penso ci sia nient'altro che tu possa fare se non testare che le funzioni all'interno di quel metodo sono chiamate.

Poiché il metodo di "orchestrazione" non contiene molta logica, il test delle unità non è così importante. È un metodo che collega solo altri metodi. Integra altri componenti. Pertanto dovrebbero esserci test di integrazione che coprano quelle linee di codice. Le unit test possono essere omesse. Quindi non me ne preoccuperei troppo se hai quei test di integrazione. Tuttavia, il modo in cui questo può essere testato per l'integrazione è un altro argomento, perché non si dovrebbero prendere in giro tutti gli altri componenti e quindi ottenere alcune dipendenze con cui si dovrà fare i conti.

    
risposta data 29.01.2015 - 10:03
fonte
2

Generalmente non è necessario testare le classi di controller, poiché non dovrebbero mantenere una logica complessa. Il lavoro effettivo dovrebbe essere fatto in altre classi se è scritto correttamente, quindi alla fine stai essenzialmente garantendo che il lavoro venga delegato correttamente.

La complessità di questo dipende interamente dal linguaggio che stai usando, dal momento che per farlo correttamente, devi creare degli stub. Lingue come Java potrebbero avere difficoltà con questo, ma ci sono librerie che ti aiutano con questo tipo Mockito .

Se hai bisogno di testare la tua classe controller, allora dovresti rimuovere idealmente le classi circostanti e mettere le classi stub al loro posto, quindi devi semplicemente verificare che il metodo corretto venga chiamato in risposta a ogni input della classe controller. Vi ricordo che l'intero punto del test unitario è verificare che ogni metodo svolga correttamente il proprio lavoro. Per una classe controller, in genere significa delegare correttamente le attività.

L'alternativa all'utilizzo di stub sarebbe quella di eseguire il lavoro effettivo, anche se questo può facilmente essere travolgente da testare data la complessità e altre complicazioni come scrivere sul database, quindi vorrei sconsigliarlo.

Inoltre, ti consiglio vivamente di estrarre solo le informazioni richieste nelle classi del controller web e di passarle ai metodi che eseguono la logica. La ragione di ciò è che non devi simulare gli oggetti http di richiesta e risposta, ma solo quello che passi, e non dovresti provare un metodo che recuperi senza problemi i dati richiesti e lo passa ad un altro metodo (se passa un valore nullo, bene, non testare più di quello che devi fare).

Spero che ti aiuti!

    
risposta data 29.01.2015 - 10:04
fonte

Leggi altre domande sui tag