Determinazione del modo migliore (o modi) di aggiungere test unitari a un progetto di grandi dimensioni che faccia buon uso delle stored procedure

7

Lavoriamo su una piattaforma di casinò / giochi / portafoglio / lotteria abbastanza grande. È un'applicazione chiavi in mano attualmente utilizzata da 4 client e presto sarà molto di più. Ho creato alcuni punti elenco relativi all'architettura sottostante:

  • ~ 130K LOC in solo codice C #
  • oltre 500 processi memorizzati, in uno dei 5 database utilizzati dal nostro sistema - poiché il nostro codice viene utilizzato in ambienti regolamentati, il codice sorgente è "bloccato" per alcuni client fino a quando non viene esaminato da un'agenzia esterna (molto costosa), quindi apportare modifiche tramite stored proc è un buon bilanciamento per mantenere felici sia i regolatori che i clienti. Gli altri database non sono vicini alla complessità del database "principale".
  • Codice dell'applicazione C #, distribuito in Windows Form, Xamarin Android, servizi Windows, app Web, libreria CLR SQL, librerie di classi e progetti di test unitari
  • Utilizza EF6 per il livello dati, alcuni ad-hoc, alcuni processi memorizzati

Mentre abbiamo alcuni test unitari in atto, è principalmente per roba relativa alle infrastrutture. Non ci sono molti test che testano le funzionalità aziendali. L'altro problema è che molti lavori pesanti vengono eseguiti nelle procedure memorizzate. È giunto il momento di aggiungere alcuni test unitari prima di iniziare a rifattorizzare parte del codice, per evitare regressioni. Quello che sto cercando è un elenco dei diversi modi per farlo. Questo è quello che ho inventato finora:

  • Abbiamo un'istanza di SQL Server "Test" che potremmo impostare per cancellare e ripopolare i dati all'avvio di ciascun test.
    • Pro
      • Lo script di dati di cancellazione / ricarica può essere facilmente modificato quando si aggiungono nuovi test
    • Contro
      • Lo script clear / reload potrebbe diventare enorme
      • I test potrebbero essere lenti a causa della cancellazione / ricarica dei dati su ogni prova di test
  • Potremmo usare Moq per deridere il contesto dei dati EF6 come ho letto su SO
    • Pro
      • Il test sarebbe veloce dato che i dati verrebbero dal codice C # e saranno compilati
    • Contro
      • L'aggiunta di dati di test in C # richiederebbe sempre
  • Utilizzare il metodo più semplice per testare i proc # C che non utilizzano stored procedure e utilizzare il prodotto di test SQL di Redgate per testare le procedure SQL da solo
    • Pro
      • Incerto. Pur possedendo la suite di sviluppo dei prodotti Redgate, non abbiamo mai utilizzato il test SQL.
    • Contro
      • Non è una vera prova del funzionamento interno dei procs a mio parere
  • Crea un nuovo override del contesto di dati EF che carica forzatamente i database sul server QA, crea un nuovo SqlTransaction sulla connessione e, quando viene eliminato, chiama Rollback per eliminare eventuali modifiche apportate
    • Pro
      • Non richiede molte modifiche a molti interni del codice esistente o refactoring
    • Contro
      • Richiede che noi refactoring un gruppo di codice per prendere una connessione al database piuttosto che consentirne la creazione, ad es. creare un IOC per ottenere la connessione al database

Il piano che ho è quello di fare un paio di buoni test scritti, e se un sacco di refactoring non è nelle carte, il nostro addetto al controllo qualità impara a programmare scrivendo dei test basati sugli esempi fatti durante l'impostazione.

Come dovrei gestire l'aggiunta di test di unità a un progetto di grandi dimensioni? Come dovrei gestire le procedure di test che chiamano stored procedure in un database? Quello che mi piacerebbe sapere è il modo migliore per eseguire lo shim unit test senza un sacco di refactoring. Rifattorizzare questo codice per disaccoppiare il livello dati, per alcuni punti, non sarebbe difficile, ma in altri punti sarebbe difficile da fare, quindi il metodo con la minore quantità di attrito sarebbe il migliore.

    
posta Derreck Dean 03.11.2016 - 19:46
fonte

1 risposta

5

Una stored procedure e il codice C # che lo utilizza sono unità diverse, quindi un singolo test di unità non può testarli entrambi. Avrai bisogno di test separati delle unità:

  • Test unitari che prendono in giro la stored procedure e verifica che il codice C # lo usi correttamente.
  • Test unitari che attivano la procedura memorizzata nello stesso modo in cui il codice C # lo attiva (se vuoi davvero puoi dire che deride il codice C #) e verifica che la stored procedure faccia quello che dovrebbe fare.

I test unitari in entrambi i proiettili presuppongono che l'interfaccia tra il codice C # e le stored procedure rimanga la stessa. Ma se hai in programma di refactoring, ci sono buone probabilità che tu voglia refactoring di quell'interfaccia! I test unitari non ti proteggeranno allora: se l'interfaccia cambia entrambi i mock non sono aggiornati e i test dovranno essere riscritti!

Suggerisco che invece di concentrarsi sui test unitari dovresti concentrarti maggiormente sui test di integrazione. Ciò significa che un singolo test può testare sia il codice C # che la stored procedure utilizzata. Ciò significa anche che non è necessario prendere in giro il database (solo i dati), quindi scrivere i test sarà molto più semplice.

Verifica se è possibile utilizzare le transazioni in ciascun test. BEGIN della transazione prima di iniziare il test e dopo il test ROLLBACK della transazione. In questo modo non dovrai ripopolare il database per ogni test: ogni test della sessione utilizzerà lo stesso database iniziale e il framework verrà ripulito dopo di esso.

    
risposta data 04.11.2016 - 00:51
fonte