Test di codice intensivo per i dati con Go, parte 4

Panoramica

Questa è la parte quattro su cinque in una serie di tutorial sul test del codice ad alta intensità di dati con Go. Nella terza parte ho coperto i test con un livello dati complesso locale che include un DB relazionale e una cache Redis.

In questo tutorial, esaminerò gli archivi di dati remoti utilizzando database di test condivisi, utilizzando le istantanee dei dati di produzione e generando i propri dati di test.

Test contro archivi dati remoti

Finora, tutti i nostri test sono stati condotti localmente. A volte, non è abbastanza. Potrebbe essere necessario testare dati difficili da generare o da ottenere localmente. I dati del test possono essere molto grandi o cambiare frequentemente (ad esempio, snapshot dei dati di produzione).

In questi casi, potrebbe essere troppo lento e costoso per ogni sviluppatore copiare i dati di test più recenti sulla propria macchina. A volte, i dati del test sono sensibili e in particolare gli sviluppatori remoti non dovrebbero averli sul proprio laptop.

Ci sono diverse opzioni qui da considerare. Puoi utilizzare una o più di queste opzioni in diverse situazioni.

Database di test condivisi

Questa è un'opzione molto comune. Esiste un database di test condiviso a cui tutti gli sviluppatori possono connettersi e testare. Questo DB di test condiviso viene gestito come risorsa condivisa e spesso viene popolato periodicamente con alcuni dati di base, quindi gli sviluppatori possono eseguire test su di esso che eseguono query sui dati esistenti. Possono anche creare, aggiornare ed eliminare i propri dati di test.

In questo caso, hai bisogno di molta disciplina e di un buon processo. Se due sviluppatori eseguono lo stesso test nello stesso momento in cui crea ed elimina gli stessi oggetti, entrambi i test non avranno esito positivo. Nota che anche se sei l'unico sviluppatore e uno dei tuoi test non si ripulisce correttamente da solo, il tuo prossimo test potrebbe fallire perché il DB ora ha alcuni dati extra del test precedente che possono interrompere il tuo test corrente. 

Esecuzione remota dei test

Ecco come funzionano le condutture CI / CD o anche solo i sistemi di compilazione automatizzati. Uno sviluppatore commette una modifica e viene avviata una build e un test automatici. Ma puoi anche connetterti a un computer remoto con il tuo codice e eseguire i tuoi test lì.

Il vantaggio è che è possibile replicare l'esatta configurazione locale, ma avere accesso ai dati già disponibili nell'ambiente remoto. Lo svantaggio è che non puoi usare i tuoi strumenti preferiti per il debug.

Istanza di test remota ad-hoc

L'avvio di un'istanza di test ad hoc remota assicura che tu sia ancora isolato da altri sviluppatori. È concettualmente molto simile all'esecuzione di un'istanza locale. È ancora necessario avviare il tuo archivio dati (o negozi). Hai ancora bisogno di popolarli (da remoto). Tuttavia, il codice di test viene eseguito localmente e puoi eseguire il debug e risolvere i problemi utilizzando il tuo IDE preferito (Gogland nel mio caso). Può essere difficile da gestire a livello operativo se gli sviluppatori mantengono le istanze di test in esecuzione al termine dei test.

Utilizzo delle istantanee dei dati di produzione

Quando si utilizza un archivio dati di test condiviso, viene spesso popolato con snapshot dei dati di produzione. A seconda di quanto sensibili e critici siano i dati, alcuni dei seguenti pro e contro possono essere rilevanti.

Pro e contro dell'utilizzo dei dati di produzione per i test

Professionisti:

  • Metti alla prova i dati reali. Se funziona, sei bravo.
  • È possibile caricare e testare i dati delle prestazioni che rappresentano un carico effettivo.
  • Non è necessario scrivere generatori di dati che tentano di simulare i dati di produzione reali.

Contro:

  • Potrebbe non essere facile testare le condizioni di errore.
  • I dati di produzione potrebbero essere sensibili e richiedere un trattamento speciale.
  • È necessario scrivere del codice o sincronizzare manualmente lo snapshot periodicamente.
  • Devi gestire le modifiche al formato o allo schema.
  • Può essere difficile isolare i problemi che si presentano con dati di produzione disordinati.

Anonimizzazione dei dati di produzione

OK. Hai fatto il salto e hai deciso di utilizzare un'istantanea dei dati di produzione. Se i tuoi dati coinvolgono esseri umani in qualsiasi forma o forma, potresti dover rendere anonimi i dati. Questo è sorprendentemente difficile.

Non puoi semplicemente sostituire tutti i nomi e averne fatto. Esistono molti modi per recuperare informazioni personali (informazioni identificabili personalmente) e informazioni personali (informazioni sanitarie protette) da snapshot di dati mal resi anonimi. Consulta Wikipedia come punto di partenza se sei curioso.

Lavoro per Helix dove sviluppiamo una piattaforma di genomica personale che tratta i dati più privati: il DNA sequenziato delle persone. Abbiamo alcune importanti protezioni contro le violazioni accidentali (e dannose) dei dati.

Aggiornamento di test e istantanee di dati

Quando si utilizzano le istantanee dei dati di produzione, è necessario aggiornare periodicamente le istantanee e corrispondentemente i test. Il tempismo spetta a te, ma sicuramente farlo ogni volta che c'è uno schema o un cambiamento di formato. 

Idealmente, i test non dovrebbero verificare le proprietà di una particolare istantanea. Ad esempio, se si aggiornano le istantanee quotidianamente e si dispone di un test che verifica il numero di record nell'istantanea, è necessario aggiornare questo test ogni giorno. È molto meglio scrivere i test in un modo più generico, quindi è necessario aggiornarli solo quando il codice in prova cambia. 

Generazione di dati di prova

Un altro approccio sta generando i propri dati di test. I pro e i contro sono gli opposti esatti dell'utilizzo di snapshot dei dati di produzione. Si noti che è anche possibile combinare i due approcci ed eseguire alcuni test su snapshot dei dati di produzione e altri test utilizzando i dati generati.

Generazione di dati di test casuali

Come faresti a generare i tuoi dati di test? Puoi scatenarti e utilizzare dati totalmente casuali. Ad esempio, per Songify possiamo generare stringhe totalmente casuali per email, URL, descrizioni ed etichette utente. Il risultato sarà caotico, ma dati validi poiché Songify non esegue alcuna convalida dei dati.

Ecco una semplice funzione per generare stringhe casuali:

func makeRandomString (length int) string const bytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" randBytes: = make ([] byte, lunghezza) per i: = 0; io < length; i++  b := bytes[rand.Intn(len(bytes))] randBytes[i] = b  return string(randBytes) 

Scriviamo una funzione che aggiunge cinque utenti casuali e quindi aggiunge 100 brani casuali distribuiti casualmente tra i cinque utenti. Dobbiamo generare utenti perché le canzoni non vivono nel vuoto. Ogni canzone è sempre associata ad almeno un utente.

func (m * InMemoryDataLayer) PopulateWithRandomData () users: = [] Utente  // Crea 5 utenti per i: = 0; io < 5; i++  name := makeRandomString(15) u := User Email: name + "@" + makeRandomString(12) + ".com", Name: makeRandomString(17),  m.CreateUser(u) users = append(users, u)  // Create 100 songs and associate randomly with // one of the 5 users for i := 0; i < 100; i++  user := users[rand.Intn(len(users))] song := Song Url: fmt.Sprintf("http://www.%s.com", makeRandomString(13)), Name: makeRandomString(16),  m.AddSong(user, song, []Label)   

Ora possiamo scrivere alcuni test che gestiscono molti dati. Ad esempio, ecco un test che verifica che possiamo ottenere tutte le 100 canzoni in una sola chiamata. Si noti che le chiamate di prova PopulateWithRandomData () prima di effettuare la chiamata. 

func TestGetSongs (t * testing.T) dl, err: = NewInMemoryDataLayer () se err! = nil t.Error ("Impossibile creare il livello dati in memoria") dl.PopulateWithRandomData () songs, err: = dl.GetSongs () se err! = nil t.Error ("Impossibile creare il livello dati in memoria") if len (songs)! = 100 tEError ('GetSongs () non ha restituito il corretto numero di brani ') 

Generazione di dati di test basati su regole

Di solito, i dati completamente casuali non sono accettabili. Ogni archivio dati presenta vincoli da rispettare e relazioni complesse che devono essere seguite per creare dati validi su cui il sistema può operare. Potresti voler generare anche alcuni dati non validi per verificare come il sistema lo gestisce, ma quelli saranno errori specifici che ti verranno iniettati.

L'approccio sarà simile alla generazione casuale dei dati, tranne per il fatto che avrai più logica per applicare le regole. 

Ad esempio, supponiamo di voler applicare la regola che un utente può avere al massimo 30 brani. Invece di creare casualmente 100 canzoni e assegnarle agli utenti, possiamo decidere che ogni utente avrà esattamente 20 canzoni, o forse creare un utente senza canzoni e altri quattro utenti con 25 canzoni ciascuno. 

Generazione di dati di test basati sulla narrativa

In alcuni casi, la generazione di dati di test è molto complicata. Recentemente ho lavorato a un progetto che doveva iniettare i dati dei test su quattro diversi micro-servizi, ognuno dei quali gestiva il proprio database con i dati in ogni database relativo ai dati in altri database. È stato piuttosto impegnativo e laborioso mantenere tutto sincronizzato.

Di solito, in tali situazioni è più facile utilizzare le API di sistema e gli strumenti esistenti che creano dati invece di andare direttamente in più archivi di dati e pregare che non si strappi il tessuto dell'universo. Non abbiamo potuto adottare questo approccio perché in realtà dovevamo creare intenzionalmente alcuni dati non validi per testare varie condizioni di errore e saltare alcuni effetti collaterali sui sistemi esterni che si verificano durante il normale flusso di lavoro. 

Conclusione

In questo tutorial, abbiamo coperto i test sugli archivi dati remoti, utilizzando database di test condivisi, utilizzando le istantanee dei dati di produzione e generando i propri dati di test.

Nella parte cinque ci concentreremo sui test fuzz, testare la cache, testare l'integrità dei dati, testare l'idempotenza e dati mancanti. Rimanete sintonizzati.