2011-12-28 4 views
6

Scrivo test di unità per livello di servizio nella mia applicazione di molla.
Qui è la mia classe di servizioTest unitari con Mockito

@Service 
    public class StubRequestService implements RequestService {  
     @Autowired 
     private RequestDao requestDao; 

     @Transactional(propagation = Propagation.REQUIRED, readOnly = true) 
     @Override 
     public Request getRequest(Long RequestId) { 
      Request dataRequest = requestDao.find(requestId); 
      return dataRequest; 
     } 
    } 

Qui è la mia classe di test

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" }) 
public class StubRequestServiceTest { 

    @Mock 
    public RequestDao requestDao; 

    StubRequestService stubRequestService; // How can we Autowire this ? 

    @org.junit.Before 
    public void init() { 
     stubRequestService = new StubRequestService(); // to avoid this 
     stubRequestService.setRequestDao(dataRequestDao); 
     // Is it necessary to explicitly set all autowired elements ? 
     // If I comment/remove above setter then I get nullPointerException 
    } 

    @Test 
    public void testGetRequest() { 
     Request request = new Request(); 
     request.setPatientCnt("3"); 
     when(requestDao.find(anyLong())).thenReturn(request); 
     assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3); 
    }  
} 

il suo bel lavoro, ma ho alcune domande

  1. Come possiamo Autowire classe di servizio in test? Sto usando il costruttore nel metodo init() per creare l'oggetto servizio.
  2. Dobbiamo impostare tutto l'elemento Autowire per la classe di servizio? Per l'ex StubRequestService è stato attivato automaticamente RequestDao che ho bisogno di impostare in modo esplicito prima di chiamare il metodo di prova altrimenti ha dato nullPointerException come requestDao è null nel metodo StubRequestService.getRequest.
  3. Quali sono le buone pratiche da seguire durante il collaudo unitario del livello di servizio Spring? (Se sto facendo qualcosa di sbagliato).
+0

Se si cambia la tua domanda dopo che le risposte sono date, le risposte non fanno più molto senso. Ritirerò la tua ultima modifica. –

+0

@ JB: scuse per la modifica della domanda. Volevo solo fornire informazioni corrette e precise. Grazie – xyz

risposta

3
  1. Se ritieni che renderà i tuoi test più facili da capire, puoi inizializzare un contesto primaverile e recuperare tutti gli oggetti da lì. Tuttavia, di solito è necessario creare un file XML di configurazione a molla separato specifico per i test, quindi non lo consiglierei.

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml"); 
    stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean"); 
    
  2. (e 3) In sostanza, io preferisco testare ogni componente della mia applicazione in totale isolamento l'uno dall'altro ed è per questo io non consiglio quello che ho descritto in [1].

Ciò significa, è si prende una fetta logica separata della vostra applicazione e prova solo, mentre completamente beffardo ogni cosa si prova ad accedere.

Diciamo che avere tre classi:

//Fetches stuff from some webservice and converts to your app domain POJOs 
class DataAccessLayer { 
    public void setWebservice(Webservice ws) {...}; 

    public MyObject getMyObject() {...}; 
} 

//Formats the domain POJOs and sends them to some kind of outputstream or stuff. 
class ViewLayer { 
    public void setOutputStream(OutputStream os) {...}; 

    public void viewMyObject(MyObject mo) {...}; 
} 

//Main entry point of our MyObject fetch-process-display workflow 
class Controller { 
    public void setDataAccessLayer(DataAccessLayer dal) {...}; 
    public void setViewLayer(ViewLayer vl) {...}; 

    public void showMyObject() { 
     MyObject mo = dal.getMyObject(); 
     ...some processing here maybe... 
     vl.viewMyObject(mo); 
    } 
} 

Ora, quali test possiamo scrivere qui?

  1. prova se DataAccessLayer converte correttamente l'oggetto da deriso fino WS al nostro oggetto di dominio.
  2. Test se ViewLayer formatta correttamente l'oggetto a lui assegnato e lo scrive su simulato sullo stream di output.
  3. prova se Controller prende un oggetto dal deriso finoDataAccessLayer processi in modo corretto e lo invia al deriso finoViewLayer.
+0

Esiste un motivo specifico per utilizzare un file di contesto diverso per istanziare il bean nel test? E grazie per esempio. Mi ha davvero aiutato molto. – xyz

+0

Non c'è motivo, è solo che in genere accade che sia incompatibile con i tuoi test. Ad esempio richiede alcune risorse JNDI, forse carica alcuni database (e i test non li usano mai), forse un po 'di sicurezza. Quindi alla fine si inizia semplicemente a notare che è più semplice creare un file di contesto separato per i test. – bezmax

+0

Sì, c'è un motivo: non si desidera testare un servizio con il vero DAO. Vuoi un finto DAO per testare il servizio. Ma segui i consigli di Max e miei: non utilizzare un contesto di primavera per i servizi di test unitario. Si potrebbe desiderare un contesto Spring per iniettare un'origine dati, SessionFactory e TxManager nei test DAO, ma non nei test di servizio. –

7

Il test è a posto. Non ha nemmeno bisogno di avere l'annotazione @ContextConfiguration.

L'intero concetto di framework di distribuzione delle dipendenze, come Spring, deve essere in grado di riunire i servizi di test semplicemente istanziandoli, impostando false dipendenze e quindi chiamando i loro metodi.

Lo stai facendo correttamente. Non è necessario disporre di un contesto di primavera per tali test unitari. Ecco perché sono chiamati unit test: lo testano in isolamento di tutte le loro dipendenze reali, inclusa la primavera.

Nota a margine: presupponendo che si stia utilizzando JUnit, gli argomenti del metodo assertXxx devono essere invertiti. Il valore previsto viene prima del valore effettivo. Diventa importante quando l'asserzione fallisce e hai un messaggio tipo "aspettarti 6 ma era 3" invece di "aspettarti 3 ma era 6".

+0

Grazie per la risposta e il suggerimento. Significa che dovremmo creare esplicitamente un oggetto servizio e impostare tutta la dipendenza autowired? Mi viene consigliato di autowire invece di impostarlo manualmente. – xyz

+1

Autowiring è OK quando si esegue l'applicazione. Non è necessario, o nemmeno desiderato, quando si esegue il test delle unità, poiché ogni test vorrà iniettare le proprie dipendenze derise. –