8

Sto tentando di configurare SpecFlow per i test di integrazione/accettazione. Il nostro prodotto ha un database di supporto (non uno enorme però) in Sqlite.Test dell'integrazione SpecFlow con modelli di database

Questo in realtà si sta dimostrando un punto leggermente appiccicoso; come modellare il database per i test?

Mi piacerebbe sapere quali sono gli schemi utilizzati da altri per eseguire test di integrazione/accettazione con i database di backup.

mi vengono in mente i seguenti approcci:

  1. compilare un database nel gruppo con i test, poi ombra-copiarla per ogni test. Sembra lento però.
  2. Potrei creare il database in memoria e popolarlo con dati predeterminati.
  3. Potrei creare il database in memoria e in qualche modo avere Givens popolare il database. Questo sembra che gonfiasse i test in modo orribile, ma potrebbe dare loro un maggiore controllo e rendere i test meno fragili.
  4. Potrei astrarre ogni interazione di database e utilizzare i mock. Non sono innamorato di questa idea dato che mi piacerebbe usarlo per testare anche le interazioni del database.
  5. Compilare il database nei test e fare affidamento sul codice di pulizia per riportarlo allo stato di base (questo sembra poco sicuro per me). Non voglio farlo con le transazioni poiché ci saranno interazioni multiple con alcuni test (quindi scrivi un elemento quindi prova a leggerlo con diversi privilegi).

risposta

4

Prima di considerare l'Come per testare, penso che si potrebbe trovare utile guardare Cosa si desidera testare.

A partire da quali dati, trovo che sia davvero utile prendere un singolo elemento, o un numero piccolo, e immaginare una serie di eventi intorno a loro in modo da darti i giusti dati di test per eseguire i tuoi test con . Per esempio;

  • Se si sta lavorando su un sistema sanitario, è possibile definire una persona "Bob" e quindi produrre i suoi eventi della vita. Bob è nato 37 anni fa oggi, cadde dalla bicicletta da bambino e si è rotto un braccio, si è sposato e ha due figli.
  • Se stai lavorando su un sistema di trading finanziario, potresti guardare un giorno tra l'apertura e la chiusura di un paio di azioni, ad es. "MSFT" e "APPL". In questo giorno potresti vedere uno che inizia basso e sale, l'altro che inizia alto e in caduta. Viene fuori una notizia che inverte le loro fortune.

Ora hai ciò che puoi effettivamente valutare quali dei tuoi scenari funzionano effettivamente per i tuoi dati, ad es. "MSFT" e "APPL" potrebbero avere 1.000 variazioni di prezzo durante il giorno, quindi generare Givens e Mock richiederebbe molto tempo. Questi dati si prestano ad essere pre-catturati. D'altro canto, i dati "Bob" funzionano particolarmente bene quando si utilizzano dati generati perché i dati possono sempre cambiare in modo che sia il suo compleanno oggi.

Una cosa che la tua domanda non sembra dover prendere in considerazione è l'aggiornamento dei dati. Ad esempio potresti voler avere una serie di test che funzionano in varie fasi del ciclo di vita delle tue entità, ad es. Alcuni test hanno a che fare con "Baby Bob", altri con "10 anni Bob" o "Married Bob" ecc.Se il tuo DB è di sola lettura, questo non è un problema se puoi scrivere i tuoi test in modo che non siano semplicemente vedi gli altri dati, ma a volte vuoi costruire una storia attraverso i tuoi test. Se i tuoi test cambiano i dati, avrai problemi nell'assicurare che i test siano eseguiti in ordine (vedi MSTest OrderedTest o mbUnit DependsOn), o che puoi separare i test in modo che ciascuno di essi gestisca un'entità dati isolata (questo è corretto se la tua entità può essere descritta in una singola riga, ma diventa più difficile quando devi leggere molte tabelle per ottenerla).

Si potrebbe anche prendere in considerazione quale codice si sta testando, è possibile variare l'approccio all'interno dei diversi set di test. Attualmente lavoro su un'applicazione multilivello con viste dell'interfaccia utente, modelli di vista, modelli client, più sistemi di comunicazione e modelli di server. Ho anche diversi set di test per questi. Ho alcuni test che funzionano su un singolo livello, prendendo in giro altri livelli per mantenere i miei test piccoli. Altri test attivano un server locale e un client locale e collegano direttamente i due. Finalmente ho alcuni test che avviano un processo completo del server, comunicano via EMS ed eseguono alcune semplici operazioni lato client usando tutto tranne le Viste dell'interfaccia utente.

Così ora per rispondere alla tua domanda in realtà,

  1. Ombra copiare il database - Sì, ho fatto una volta con SQLServer Developer e aveva un xxx.mdb che ha ottenuto copiato prima di eseguire i test . Tuttavia alcuni moderni framework di test eseguiranno test in parallelo, ad es. NCrunch, quindi questo si rompe.
  2. Creare il database e precompilare - Non eseguito questo, ma i miei dubbi sarebbero ciò che accade dove un test cambia il database in uno stato imprevisto. Altri test falliranno quando non avranno fatto nulla di sbagliato.
  3. creare il database e utilizzare Givens - ho fatto questo con NUnit tramite [SetupFixture] sulla cima di una DB.You LINQ to SQL hanno ancora preoccupazioni per corse di prova in parallelo e si deve bilanciare la granularità dei tuoi Givens (vedi StackOverflow-When do BDD scenarios become too specific), e si ha il problema di ordinare i dati di aggiornamento/isolamento dei dati, ma questo può funzionare molto bene per consentire di lavorare attraverso le storie dei dati e far crescere i dati durante i test. D'altro canto, se un test fallisce e lascia i dati in cattivo stato, si possono finire con molti fallimenti, ma almeno è sufficiente guardare prima quello che fallisce. Questo tipo di test non sarà riprodotto molto bene per gli sviluppatori sulla loro workstation in quanto non possono semplicemente eseguire un singolo test, in particolare con strumenti come NCrunch, che può solo eseguire test il cui codice è cambiato.
  4. Mock the database Ecco come ho scelto di fare le cose ora. Il trucco è che se si sta seguendo personalmente un processo TDD ragionevolmente rigoroso in cui si verifica solo il metodo su cui si sta lavorando, si finisce in realtà con alcuni livelli che testano l'interazione del database, ad es. [Test]DALLayerTests.ShouldReadARowAndCreatePOCO(), ma la maggior parte degli altri ha utilizzato dati falsi per verificare ciò che effettivamente accade, ad es. [Test]BusinessObjectPersonTests.ShouldGetBirthdayCongratulations().
  5. Usa ripulire il codice - Mai provato, sembra poco raccomandabile :-)
+0

Re: punto 4: test di integrazione, per definizione, non sono test di unità. I test unitari conducono test per comportamenti (o stati) di oggetti isolati dal resto del sistema (da qui il termine "unità"). I test di integrazione, d'altra parte, sono pensati per esercitare il flusso di dati e i processi di business risultanti (logica) tra le unità - testandoli insieme (da qui il termine "integrazione"). Pertanto, è perfettamente ragionevole accedere a un database quando si eseguono test di integrazione. Inoltre, non prendere in giro ciò che non possiedi, quindi non prendere in giro il database. – fourpastmidnight

+1

In realtà, fai schifo a ciò che non possiedi!Scrivere test significa verificare il comportamento che controlli. Se non ci si può fidare del fatto che il proprio database funzioni come richiesto, si genereranno segnalazioni di bug con il proprio fornitore, non risolvendo il codice. Ma cosa succede se non è un DB, ma invece un prodotto di un'altra squadra nella tua organizzazione? Vuoi che i tuoi test falliscano perché il codice è sbagliato? In realtà potresti, ma hai bisogno di alcuni test per evidenziare che il tuo codice interno funziona, e fallisce quando si connette al loro sistema. – AlSki

+0

Sono d'accordo con te anche quando dici che è ragionevole accedere a un database quando si eseguono test di integrazione, ma il contesto di questa domanda è quali alternative e insidie ​​ci sono in questi scenari. – AlSki

Problemi correlati