Sistemi di test unitari con logica strettamente accoppiati a dati

3

Capisco che ci sono molte domande in questo sito che ruotano attorno allo stesso concetto, ma non ho potuto ottenere una risposta precisa per il mio caso.

Problema

Sto gestendo un sistema ERP, con codice base in entrambi:

  • VB.NET/ASP Moduli per la parte dell'interfaccia utente del sistema
  • Stored procedure TSQL su SQL Server, gestione della logica aziendale.

Quindi, sia le tabelle di database che le stored procedure di database accoppiano strettamente dati e business logic

Abbiamo cercato di individuare un modo per automatizzare i test unitari per aiutarci a rilevare regressione e altri potenziali bug. Ma il problema con il nostro setup è la presenza del database come componente principale della logica di business del nostro sistema; I database conservano gli stati, cioè non possiamo eseguire qualcosa come xUnità con classi indipendenti. poiché ogni test modifica lo stato del nostro sistema, modificando uno dei record delle tabelle dati, delle tabelle di ricerca o delle tabelle di controllo.

Vincoli

Non ci aspettiamo di spostare la nostra logica nella porzione VB del nostro codice ( Per ragioni politiche )

Si noti che il database di simulazione non risolverà il nostro problema, perché la logica aziendale viene eseguita su stored procedure, ovvero in base alla progettazione basata sullo stato dei dati

Domanda

Quali sono le nostre opzioni?

  • c'è un modo per implementare test automatici di integrazione / unità?
  • Siamo bloccati nel test manuale?
  • Dovremmo posizionare il nostro ambiente in una farm di macchine virtuali con la stessa linea di base ed eseguire test indipendenti su macchine diverse?

Purtroppo non sono riuscito a trovare alcuna documentazione relativa alle migliori pratiche per i sistemi basati su TDD e Stored Procedures.

    
posta A.Rashad 22.08.2017 - 14:59
fonte

4 risposte

8

Ho implementato test automatici incluso il database in un sistema con alcuni degli stessi problemi. L'approccio che ho seguito è stato approssimativamente:

  • Prima di tutti i test unitari, crea un DB da zero con schema e nessun dato
  • Prima di ogni caso di test, troncare tutte le tabelle db pertinenti

Funziona, anche se produce molto lenti test

Dopo aver eseguito i test di regressione / caratterizzazione, è necessario iniziare a disaccoppiare la logica dell'applicazione dal database. Nascondere la logica aziendale dietro un'interfaccia e utilizzare l'inversione del controllo in modo da poter passare all'implementazione. Inizierai con l'implementazione con db-backed e nei test puoi utilizzare una versione in-memory più leggera e più veloce.

Ad esempio, se hai:

def frob_widgets(foo, bar):
    if db.some_query(params=blah):
        foo.flip()
    bar.calcinate(foo)
    return db.explode(bar, foo)

Cambia la firma in def frob_widgets(db, foo, bar)

Potresti trovare uno strumento come ephemeral_pg utile, che aiuta a eseguire un database postgres il più semplice possibile eseguendo in memoria con minori controlli di sicurezza / affidabilità abilitati

    
risposta data 22.08.2017 - 15:06
fonte
4

Supponendo che tutta la logica sia all'interno del tuo DB, nelle stored procedure, e semplicemente non puoi cambiarla nel tuo progetto, farei quanto segue:

  1. (facoltativo) Rifattora le tue stored procedure in modo che ognuna abbia una chiara responsabilità e che puoi mapparla per un input A, ci sarà un output (o alcuni dati specifici in una tabella) B;
  2. avere un database di test, in cui cancellare tutti i dati e inserire al volo dati specifici durante l'esecuzione dei test unitari;
  3. Con ciò, crea i tuoi test unitari come stored procedure e anche stored procedure per inserire dati di input specifici (input A dal passaggio 1) e stored procedure per cancellare tutti i dati correnti;
  4. Ciascuna procedura di test (unit test) verifica una delle tue stored procedure logiche e inserisce i dati come input A e si aspetta che la procedura generi dati di output come output B, se questo viene eseguito, allora il test PASSES, altrimenti FAILS;
  5. (opzionale) le procedure di test esistono solo nel database di test; potresti anche avere una tabella UnitTests separata, che contiene il nome della stored procedure e il suo ultimo stato di esecuzione; con questo, è possibile creare una stored procedure UnitTestManager, che eseguirà la ricerca nella tabella UnitTests e chiamerà dinamicamente le procedure di test e aggiorna i dati di UnitTests. Successivamente, dopo l'esecuzione, puoi controllare le informazioni dettagliate su guasti e successi nella tabella UnitTests.
risposta data 22.08.2017 - 15:59
fonte
1

Puoi provare a costruire mock, matrici e falsi attorno alle tue unità come sostituto delle dipendenze.

Non ho molta esperienza con VB.NET, ma sono sicuro che ci sono framework di test unitari là fuori che puoi trovare.

Un collega mi ha recentemente indirizzato a un articolo di Martin Fowler . Spero che possa aiutarti a trovare la tua strada.

    
risposta data 22.08.2017 - 15:06
fonte
0

Ho appena pensato ad una soluzione teorica a questo problema come segue:

  1. Crea una transazione
  2. fai i tuoi test
  3. Ripristina la transazione

    Begin Transaction test_case
       -- Test Preparation Steps
       ...
       -- Assertion Steps 
       ...
    Rollback transaction test_case
    

Ciò garantirà che i test non alterino lo stato del sistema testato, a meno che, naturalmente, uno dei passaggi testati coinvolga DML.

C'è un inconveniente in questo approccio, che non possiamo salvare i risultati dei test in questo database. invece, possiamo inserire risultati in alcuni report o in un file di spool

    
risposta data 25.08.2017 - 20:39
fonte

Leggi altre domande sui tag