Domanda

Sto lavorando a un progetto Spring MVC e ho test unitari per tutti i vari componenti nella struttura dei sorgenti.

Ad esempio, se ho un controller HomeController , che deve contenere un LoginService , quindi nel test dell'unità HomeControllerTest Ho semplicemente istanziato l'oggetto normalmente (fuori da Spring) e ho iniettato la proprietà:

protected void setUp() throws Exception {
    super.setUp();
    //...
    controller = new HomeController();
    controller.setLoginService( new SimpleLoginService() );
    //...
}

Funziona benissimo per testare ogni componente come un'unità isolata - tranne ora che ho alcune dozzine di classi nel progetto, dopo aver scritto una classe e aver scritto un test unitario di successo, continuo a dimenticare di aggiornare il mio contesto MVC Spring file che esegue il cablaggio effettivo nell'applicazione distribuita. Scopro di aver dimenticato di aggiornare il file di contesto quando distribuisco il progetto su Tomcat e trovo un gruppo di NullPointer da bean non cablati.

Quindi, ecco le mie domande:

  1. Questo è il mio primo progetto Spring - è normale creare test unitari per i singoli bean, come ho fatto, e quindi creare una seconda suite di test (test di integrazione) per verificare che tutto funzioni come previsto il contesto reale dell'applicazione? Esiste una migliore pratica consolidata per questo?

  2. Inoltre, come si separano i test unitari dai test di integrazione? Ho tutto il codice sorgente in src , i test unitari in test - dovrebbe esserci una seconda cartella di test (come test-integrazione ) per i casi di test di integrazione?

Dato che questo è il mio primo progetto di primavera, sono curioso di sapere come gli altri di solito fanno questo genere di cose - e piuttosto che reinventare la ruota, chiedo piuttosto al resto della comunità.

È stato utile?

Soluzione

Non posso parlare di essere una best practice, ma ecco cosa ho fatto in passato.

Test unitari:

  • Crea test unitari per bean non banali (ovvero, la maggior parte dei tuoi bean Spring correlati)
  • Usa Mock per servizi iniettati dove possibile (cioè, la maggior parte se non sempre).
  • Utilizzare una convenzione di denominazione standard per questi test nella directory test del progetto. L'uso di Test o TestCase come prefisso o suffisso per il nome della classe sembra essere ampiamente praticato.

Test di integrazione:

  • Crea un AbstractIntegrationTestCase che configura un Spring WebApplicationContext per l'uso in clase di test di integrazione.
  • Utilizza una convenzione di denominazione per i test di integrazione nella directory test . Ho usato IntTest o IntegrationTest come prefisso o suffisso per questi test.

Imposta tre target test Ant:

  1. test-all (o come si desidera nominarlo): esegui test unità e integrazione
  2. test: esegui test unitari (solo perché test sembra essere l'uso più comune per i test unitari
  3. test-integrazione: esegui i test di integrazione.

Come notato, puoi usare le convenzioni di denominazione che hanno senso per il tuo progetto.

Per quanto riguarda la separazione delle unità dai test di integrazione in una directory separata, non credo sia importante finché gli sviluppatori e i loro strumenti riescono a trovarli ed eseguirli facilmente.

Ad esempio, l'ultimo progetto Java su cui ho lavorato con Spring ha usato esattamente ciò che è stato descritto sopra, con test di integrazione e test unitari che vivono nella stessa directory test . I progetti Grails, d'altra parte, separano esplicitamente le directory dei test di unità e integrazione in una directory di test generale.

Altri suggerimenti

Alcuni punti isolati:

Sì, è un approccio comune ai test Spring: test unitari separati e test di integrazione in cui il primo non carica alcun contesto Spring.

Per i tuoi test unitari, potresti prendere in considerazione la derisione per assicurarti che i tuoi test siano focalizzati su un modulo isolato.

Se i test eseguono il cablaggio in una tonnellata di dipendenze, in realtà non sono test unitari. Sono test di integrazione in cui si esegue il cablaggio delle dipendenze utilizzando l'iniezione nuova anziché di dipendenza. Una perdita di tempo e sforzi duplicati quando l'applicazione di produzione utilizza Spring!

I test di integrazione di base per far apparire i tuoi contesti Spring sono utili.

L'annotazione @required può aiutarti ad assicurarti di rilevare le dipendenze richieste nel tuo cablaggio Spring.

Forse cerca Maven che ti darà fasi esplicite su cui legare la tua unità e test di integrazione. Maven è ampiamente utilizzato nella comunità di primavera.

Gran parte del noioso doppio libro con la primavera scompare se passi anche a un regime puramente annotato, in cui annoti tutti i tuoi bean con @Component, @Controller, @Service e @Repository. Aggiungi @Autowired agli attributi necessari per essere iniettato.

Vedere la sezione 3.11 del manuale di riferimento della molla. http: //static.springframework. org / primavera / docs / 2.5.x / riferimento / beans.html # fagioli-annotation-config

Su una nota correlata, abbiamo utilizzato i test Divisione Unità / Integratrion descritti da KenG. Nel mio regime più recente abbiamo anche introdotto una terza "classe" di test, "Test componenti". Funzionano con cablaggio a molla completo, ma con implementazioni di stub cablate (utilizzando filtri di scansione dei componenti e annotazioni in primavera).

Il motivo per cui l'abbiamo fatto è stato perché per alcuni dei "servizi" livello si finisce con un'enorme quantità di logica di cablaggio codificata a mano per cablare manualmente il bean, e talvolta quantità ridicole di oggetti simulati. 100 linee di cablaggio per 5 linee di prova non sono rare. I test dei componenti alleviano questo problema.

Usa l'interfaccia InitializingBean (implementa un metodo "afterPropertiesSet") o specifica un metodo init per i tuoi bean. InitializingBean è in genere più semplice perché non è necessario ricordare di aggiungere il metodo init ai bean.

Usa afterPropertiesSet per assicurarti che tutto sia iniettato come non null, se è null, genera un'eccezione.

Quando ho creato i test di integrazione per le applicazioni Web, li ho inseriti in una directory separata. Sono costruiti usando jUnit o TestNG e interagiscono con il sistema in prova usando qualcosa come Selenium che colpisce le pagine web come se fossero utenti. Il ciclo andrebbe così: compilare, eseguire unit test, costruire l'app Web, distribuirla su un server in esecuzione, eseguire i test, annullare la distribuzione dell'app e riportare i risultati. L'idea è di testare l'intero sistema.

Per quanto riguarda l'esecuzione di unit test separatamente dai test di integrazione, ho inserito tutti questi ultimi in una directory di test di integrazione e li ho eseguiti utilizzando IDE / Ant usando un approccio come questo . Funziona per me.

la differenza tra test unitario e test di integrazione è che unit test non carica necessariamente il tuo contesto, ti stai concentrando sul codice che hai scritto - funziona velocemente, cioè con e senza eccezioni, deridendo qualsiasi chiamata dipendente dentro. Ma in caso di test di integrazione, carichi il contesto ed esegui test end-to-end come scenari reali.

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