Come posso utilizzare unit test e TDD per testare un'app che si basa principalmente su operazioni CRUD del database?

22

Al lavoro, uno dei miei progetti consiste principalmente nel prendere dati passati da un client esterno e persistere in un database. Si tratta di un'app enterprise Java che utilizza JPA e gran parte della nostra logica ruota attorno alle operazioni CRUD.

La maggior parte dei nostri bug riguarda JPA in un modo o nell'altro.

  • Esempio 1: se fai clic due volte sul pulsante di salvataggio, JPA potrebbe provare a inserire la stessa entità nel database una seconda volta, causando una violazione della chiave primaria.
  • Esempio 2: recuperi un'entità dal database, modificala e prova ad aggiornare i suoi dati. JPA può provare a creare una nuova istanza invece di aggiornare quella vecchia.

Spesso la soluzione ha bisogno di aggiungere / rimuovere / modificare un'annotazione JPA. Altre volte ha a che fare con la modifica della logica DAO.

Non riesco a capire come ottenere la fiducia nel nostro codice usando i test unitari e TDD. Non sono sicuro che sia perché i test unitari e TDD sono inadatti o se mi sto avvicinando al problema.

I test unitari sembrano un brutto aspetto perché posso scoprire questi problemi solo in fase di esecuzione e devo eseguire la distribuzione su un app server per riprodurre i problemi. Di solito è necessario coinvolgere il database che considero esterno alla definizione di un test unitario: si tratta di test di integrazione.

Il TDD sembra un brutto aspetto perché il ciclo di feedback del deploy + test è così lento che mi rende molto improduttivo. Il ciclo di feedback di implementazione + test richiede più di 3 minuti, e solo se eseguo i test specificatamente sul codice che sto scrivendo. Per eseguire tutti i test di integrazione occorrono 30 minuti.

C'è un codice al di fuori di questo stampo e lo collaudo sempre ogni volta che posso. Ma la maggior parte dei nostri bug e il maggior numero di sink coinvolgono sempre JPA o il database.

C'è un'altra domanda che è simile , ma se avessi seguito il consiglio avrei avvolto la parte più instabile del mio codice (il JPA) e testato tutto tranne esso. Nel contesto della mia domanda, sarei nella stessa brutta situazione. Qual è il prossimo passo dopo il wrapping del JPA? IMO quella domanda è (forse) un passo per rispondere alla mia domanda, ma non una risposta ad esso.

    
posta Daniel Kaplan 27.06.2014 - 20:23
fonte

4 risposte

7

Un'opzione consiste nell'utilizzare un database di test in memoria come H2 ; tende ad essere circa 10 volte più veloce di un database standard che utilizza dischi e con tempi di avvio / smontaggio inferiori.

Se sarà di aiuto dipende in larga misura dal fatto che i problemi JPA che si stanno avendo siano abbastanza generali da non riuscire ancora su database diversi. Non è il caso di eseguire test più velocemente se mancano la maggior parte dei problemi.

Ma se riesci a eseguire 10 sessioni con H2 per ognuna con il sistema completo, potrebbe pagare.

    
risposta data 30.06.2014 - 23:39
fonte
3

Le basi di dati possono essere molto semplici da testare unitamente: servono procedure e transazioni memorizzate.

Questo è ciò che Microsoft dice su Test dell'unità di database . È anche possibile eseguire test unitari su un database, scrivere i test in Java o C # impostando una connessione DB, iniziare una transazione, scrivere i dati che si desidera utilizzare per il test sul DB, eseguire i test e quindi eseguire il rollback. Nessun danno al DB se ne stai utilizzando uno anche a te distribuito e ottieni test completamente isolati.

Spero che questo possa darti un'idea su come farlo all'interno del tuo framework.

    
risposta data 01.07.2014 - 00:11
fonte
2

Altre persone hanno risposto con "Mock out your DB!" - Ma che senso ha deridere il tuo livello DB se hai effettivamente bisogno di testare come interagisce con il tuo codice?

Quello che stai cercando sono test di integrazione e / o test UI automatizzati. Hai detto che il problema si verifica quando:

*If you click the save button twice*

L'unico modo per testare questo è scrivere un test dell'interfaccia utente automatico per fare clic sul pulsante due volte. Forse controlla il selenio.

Probabilmente avrai bisogno anche di un DB di test delle unità e per i tuoi test puntalo verso questo. Un dolore da mantenere ma benvenuti a TDD nel mondo reale.

    
risposta data 01.07.2014 - 08:01
fonte
0

Nell'esempio che inserisci nella tua domanda, non puoi eseguire il test unitario / TDD nella situazione di fare clic sul pulsante due volte per causare un errore molto facilmente. Ma quello che puoi testare è che nel codice che viene chiamato quando fai clic sul pulsante, se ottieni un'eccezione dal livello di persistenza lo gestisci appropriatamente (sia prendendo in giro il livello di persistenza o usando un database in memoria come è stato suggerito in altre risposte) - rilanciando o visualizzando un errore o altro.

Hai ragione che TDD può iniziare a guastarsi quando devi eseguire test che non si adattano bene a un test di unità (cioè test di integrazione / di sistema) - questo ha costituito un bel po 'di discussione nel recente "TDD è morto?" dibattiti tra Kent Beck, Martin Fowler e David Heinemeier Hansson: link

    
risposta data 01.07.2014 - 10:18
fonte

Leggi altre domande sui tag