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


22

Al lavoro, uno dei miei progetti riguarda principalmente il trasferimento di dati trasmessi da un client esterno e la persistenza in un database. È un'app enterprise Java che utilizza JPA e la maggior parte della nostra logica ruota attorno alle operazioni CRUD.

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

  • Esempio 1: se si fa clic due volte sul pulsante Salva, JPA potrebbe tentare di inserire la stessa entità nel database una seconda volta, causando una violazione della chiave primaria.
  • Esempio 2: recuperare un'entità dal database, modificarlo e provare ad aggiornare i suoi dati. JPA potrebbe tentare di creare una nuova istanza invece di aggiornare quella precedente.

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

Non riesco a capire come ottenere fiducia nel nostro codice usando unit test e TDD. Non sono sicuro se è perché i test unitari e il TDD non funzionano bene o se sto affrontando il problema in modo errato.

I test unitari sembrano sbagliati perché riesco a scoprire questi problemi solo in fase di esecuzione e ho bisogno di distribuirli su un server app per riprodurre i problemi. Di solito deve essere coinvolto il database che considero al di fuori della definizione di un unit test: si tratta di test di integrazione.

TDD sembra una scelta sbagliata perché il circuito di feedback deploy + test è così lento che mi rende molto improduttivo. Il ciclo di feedback deploy + test impiega più di 3 minuti, ed è solo se eseguo i test specificamente sul codice che sto scrivendo. Per eseguire tutti i test di integrazione sono necessari oltre 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 i più grandi intervalli di tempo coinvolgono sempre JPA o il database.


C'è un'altra domanda che è simile , ma se seguissi il consiglio starei avvolgendo la parte più instabile del mio codice (JPA) e testando tutto tranne che. Nel contesto della mia domanda, mi troverei nella stessa brutta situazione. Qual è il prossimo passo dopo aver concluso l'APP? IMO quella domanda è (forse) un passo per rispondere alla mia domanda, ma non una risposta ad essa.


4
Quello che stai facendo è essenzialmente un test di integrazione, poiché devi impostare il database per testarlo. Posso immaginare che un modulo farebbe affidamento su altri, quindi rendilo ancora più simile al test di integrazione. Vorrei cambiare la domanda che hai su come applicare gli approcci TDD alla tua applicazione.
Informato il

@randomA corretto, ho modificato la mia domanda per dirlo esplicitamente. Non capisco perché mi stai raccomandando di cambiare la domanda. Puoi elaborare? Voglio mantenere la parte di unit test in là perché avrei piuttosto essere scrittura di unit test di test di integrazione (anche se sono consapevole del fatto che unit testing != TDD)
Daniel Kaplan

niente di speciale però, basta mettere TDD lì. Se hai un test unitario lì, molte persone penserebbero che non capisci la cosa, ecc. Non va bene per te ..
Informato


Risposte:


7

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

L'aiuto dipenderà in gran parte dal fatto che i problemi di JPA che stai riscontrando siano abbastanza generali da non riuscire ancora su database diversi. Non è molto importante eseguire i test più velocemente se perdono la maggior parte dei problemi.

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


È una buona idea, ma dovrei comunque distribuire sul server delle app, AFAIK. Sono molti i 3+ minuti. Detto questo, vale sicuramente la pena farlo. Ma è ancora difficile immaginare di eseguire i test tutte le volte che eseguirò i test unitari e quindi sembra inefficiente sviluppare utilizzando TDD.
Daniel Kaplan,

1
Penso che di solito ci siano modi per aggirare quel requisito (ad esempio docs.oracle.com/middleware/1212/toplink/TLADG/testingjpa.htm ). Abbastanza alte possibilità di essere più lavoro di quanto giustificato; un'altra opzione sarebbe quella di ottenere alcuni server di test più robusti ed eseguire le cose in parallelo.
soru,

1
@tieTYT La mia prova del concetto con l'unità hsqldb che verifica un'app Web grezza su github: TestingWithHsqldb - i test delle unità non richiedono l'installazione dell'app.

3

I database possono essere molto facili da testare in unità: sono necessarie procedure e transazioni memorizzate.

Questo è ciò che dice Microsoft sui test delle unità di database . Puoi anche eseguire unit test su un database, scrivere i tuoi test in Java o C # impostando una connessione DB, avviando una transazione, scrivendo tutti i dati che vuoi utilizzare per il test sul DB, eseguendo i test e quindi eseguendo il rollback. Nessun danno al DB se ne stavi usando uno che hai anche distribuito e ottieni test completamente isolati.

Spero che questo possa darti un'idea di come farlo nel tuo framework.


Come ho detto, "La maggior parte dei nostri bug riguarda l'APP in un modo o nell'altro", penso che il consiglio dell'articolo mancherebbe a tutti quelli. Inoltre, se consideri quei test Java / C # ancora come unit test, abbiamo definizioni molto diverse. Penso che questo sia un buon consiglio in generale, ma sembra che ci vorrebbe un sacco di tempo per distribuire ed eseguire la suite e quindi non favorire TDD. Non sei d'accordo?
Daniel Kaplan,

Eseguivamo test di unità DB per il nostro SQL, ma poi erano tutti in sprocs. Mentre puoi testare unit sql directory da altre procedure sql, il nostro framework di unit test era MSTest, quindi aveva senso eseguirli da lì (ehi, abbiamo ottenuto segni di spunta verdi nel server di build che era il fattore più importante). Se hai un DB sempre attivo (e lo abbiamo fatto comunque per i test int.) Allora è facile caricare tutto il codice sql ed eseguire tutti i test unitari sul server di build. A volte devi solo essere pragmatico su queste cose.
gbjbaanb,

Non credo che tu abbia risposto alla mia prima frase.
Daniel Kaplan,

bene, allora usa solo jpa-unit. Non posso rispondere a come funziona (o non funziona) il tuo codice JPA, prova solo a darti alcune idee su come testare quel sql nel db.
gbjbaanb,

3

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

Quello che stai cercando sono i test di integrazione e / o i test automatici dell'interfaccia utente. Hai detto che il problema si verifica quando:

*If you click the save button twice*

L'unico modo per verificarlo è scrivere un test UI automatizzato per fare clic due volte sul pulsante. Forse dai un'occhiata al selenio.

Probabilmente avrai anche bisogno di un DB di unit test e per i tuoi test puntalo verso quello. Un dolore da mantenere ma benvenuto nel TDD nel mondo reale.


questo sembra più un rant che una risposta
moscerino

Ho risposto alla domanda tre volte: test di integrazione, test della GUI e / o un DB di test dell'unità. Sì, è un po 'irritante, lo modificherò in una parvenza di sanità mentale adesso.
Rocklan,

1
"L'unico modo per testare questo è scrivere un test UI automatico per fare clic due volte sul pulsante. Forse dai un'occhiata a Selenium." In situazioni del genere, è meglio che il backend impedisca che ciò accada, altrimenti l'interfaccia utente avrebbe accesso diretto al database.
Daniel Kaplan,

0

Nell'esempio fornito nella domanda, non è possibile eseguire unit test / TDD sulla situazione facendo clic due volte sul pulsante per causare un errore molto facilmente. Ma ciò che puoi testare l'unità è che nel codice che viene chiamato quando fai clic sul pulsante, se ottieni un'eccezione dal livello di persistenza, lo gestisci in modo appropriato (deridendo il livello di persistenza o utilizzando un database in memoria come è stato suggerito in altre risposte) - ricodificando o visualizzando un errore o altro.

Hai ragione sul fatto che TDD può iniziare a rompersi quando è necessario eseguire test che non si adattano bene a un test unitario (ad esempio test di integrazione / sistema) - questo ha costituito un bel po 'della discussione nel recente "Is TDD Morto?" dibattiti tra Kent Beck, Martin Fowler e David Heinemeier Hansson: http://martinfowler.com/articles/is-tdd-dead/

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.