venerdì 17 febbraio 2012

Effettuare test di unità in SQL Server un cittadino di prima classe con test SQL Red Gate

Che qui non scrivere unit test abbastanza? Voglio dire altro da me? In qualche modo, non importa quanto sia buona la mia copertura di test si sono caduto come sempre ci sono alcune parti mancanti. In parte questo è perché le pratiche di unit test tende ad essere uno di quei dibattiti religiosi e se si ascolta numero sufficiente di persone, è facile convincersi che si sta facendo è sbagliato.
Un settore che è sempre stato un po 'difficile sta sperimentando qualcosa con una dipendenza database. In parte, ciò è dovuto al fatto quei test spesso finiscono per essere dipendente stesso di dati che, naturalmente, può essere altamente volatile. Ma è anche filosoficamente contestata nel senso che se uno unit test è quello di valutare un'unità distinta di codice sul livello applicazione, allora probabilmente non dovrebbe avere dipendenze livello dati.
Il problema, naturalmente, è che stiamo ancora scrivendo un sacco di logica nel livello dati.ORM Fancy sono fantastici e io sostengo il loro utilizzo nella misura massima che è pratico, ma ci sono ancora un sacco di casi d'uso per la scrittura logica di business nel database e si vuole veramente che, per essere verificabile. Inoltre, naturalmente, c'è tutto questo altro universo alternativo di persone che lavorano completamente in database e non hanno accesso agli strumenti di test molti di noi utilizzano regolarmente all'interno di Visual Studio, chiamiamoli i "cittadini di seconda classe di unit test".
Questo è dove prova SQL Red Gate entra in gioco è interamente auto-contenute in SSMS e tutto ciò che fa è la logica di business test nel database, proprio come quei cugini di prima classe in Visual Studio. Ed è totalmente rocce.

Caso d'uso

Questo non è uno di quei arioso-fiabe situazioni ipotetiche, ho davvero bisogno di spostare una certa logica nel DB così ho potuto eseguire query su ASafaWeb indipendentemente dal livello applicazione. Quello che volevo fare era scrivere una piccola funzione di accertare se una voce nel registro qualcuno aveva suggerito di eseguire una scansione contro un sito Web ASP.NET o no. Ho già in questa logica nel mio app web e sembra che in questo modo:
public static bool ?


{
  / / Nessuna informazione a tutti dovrebbe (si spera) che il sito è configurato per 
  mantenere le intestazioni in silenzio. Potrebbe andare in entrambi i casi quindi dovremo tornare null.
   se (( string IsNullOrEmpty (server). | server.Contains ( "nginx" ))
    && (XPoweredBy == nullo | |! xPoweredBy.Any ())
    && string . IsNullOrEmpty (xAspNetVersion)
    && string . IsNullOrEmpty (xAspNetMvcVersion)
    && string . IsNullOrEmpty (aspNetVersion))
  {
    restituire null ;
  }

  return
     (! stringa . IsNullOrEmpty (server) && (server.Contains ( "Microsoft-IIS" )))
    | | (! XPoweredBy = null && xPoweredBy.Any (x => x == "ASP.NET" ))
    | |! string . IsNullOrEmpty (xAspNetVersion)
    | |! string . IsNullOrEmpty (xAspNetMvcVersion)
    | |! string IsNullOrEmpty (aspNetVersion).;
}
Questo è semplicemente guardando le intestazioni di risposta e fare un guesstimation se il sito è ASP.NET o meno. No info (nginx o un server che esegue quadri che supporta multipli) significa che non ho idea e restituisce null (la prima serie di condizioni), mentre qualsiasi cosa che suggerisce IIS o ASP.NET è presente restituisce true (la seconda serie di condizioni) . Ci sono poi una serie di prove scritte intorno a questo in un progetto di test Visual Studio.

Installazione e configurazione di test SQL

Il primo passo è quello di andare a mettere le mani su di test SQL Red Gate . E 'in anteprima 2, è attualmente libero, just do it! Una volta installato e al fuoco fino SSMS, nuove cose iniziano a comparire:
Configurazione di test SQL
Prenderemo il database di esempio semplicemente perché è un buon punto di riferimento di come fare le cose per bene:
Database di esempio installato con successo
E qui andiamo, il corridore di prova viene caricato con il database di esempio:
Il corridore di test SQL che mostra le prove del database di esempio
Io non entrerò nel merito di quello che sta succedendo qui, eseguirlo su voi stessi e dare un'occhiata dentro se siete interessati. Invece, voglio aggiungere il mio database ASafaWeb ed effettivamente iniziare a testare la mia TSQL. Quando aggiungo il database, ho un dialogo bello chiaro spiegando che cosa sta per accadere:
Aggiungendo il database ASafaWeb
Ora, questo probabilmente non sarà per tutti, posso immagine che alcune persone non essere felice con un mucchio di nuove procedure, funzioni e altri oggetti che compaiono nel loro database incontaminata. Ma naturalmente si può facilmente escludere quelli di distribuzione al momento della pubblicazione via SQL Compare come ho conosciuto da fare .
Un'ultima cosa - se prendiamo il valore predefinito e includono SQL Cop test di analisi statica, siamo in grado di validare alcuni buoni principi di progettazione DB. Suoni la pena:
Aggiunta Cop SQL per la suite di test
Run che, ecco quello che ora abbiamo:
Corretta installazione di test SQL in ASafaWeb
Quali sono quindi carica il DB Up in the runner test:
Le prove ASafaWeb caricati nella il corridore
Come potete vedere, abbiamo ottenuto solo prove di Cop SQL lì per ora, ma cerchiamo di dare loro un run in ogni caso:
Due prove di Cop SQL fallimento in ASafaWeb
Uh oh, questo significa che il mio SQL non va bene? Sto DB destinato alla dannazione eterna? Fortunatamente, se diamo uno sguardo ai messaggi dal canale di prova si scopre che niente di tutto questo è colpa mia:
I messaggi di prova dopo aver fallito SQL sul database ASafaWeb
Si scopre che Microsoft si sta portato a un'attività tramite EXEC sp_executesql anziché in un paio di procedure di appartenenza del loro provider memorizzati, che è apparentemente una brutta cosa . Poi abbiamo ELMAH essere scoperti usando ROWCOUNT SET che èapparentemente destinato ad essere obsoleto (quasi cinque anni e ancora funziona bene in SQL08 ...)
Comunque, niente di tutto questo è il mio codice e non ho intenzione di andare modificare il codice generato da altre parti. Andiamo sul bit interessante.

Scrivere i test

Il primo test di base che voglio veramente è effettivamente la prima condizione stavo testando da tale codice C # di precedenza, nessuna intestazione a tutti dovrebbe restituire nulla perché non abbiamo niente da confermare o negare la presenza di ASP.NET e IIS.Facciamo scrivono che nella "New Test" il dialogo:
Creazione di un nuovo dialogo di prova
Lavorare sulle precedenti nel database di esempio, ho intenzione di creare una classe dedicata test chiamato "AspNetSiteTests". In questo modo si crea uno schema con lo stesso nome e una volta che il test è stato creato, siamo tornati in buoni TSQL vecchio con un modello di Test pronti:
- Comments qui sono associati con il test.
- Per esempi di casi di test, vedere: http://tsqlt.org/user-guide/tsqlt-tutorial/~~V
ALTER PROCEDURE [AspNetSiteTests] . [test nessuna intestazione restituisce null]
 AS
BEGIN
  - Montare
  - Questa sezione è per il codice che imposta l'ambiente. Spesso
  - Contiene le chiamate a metodi come tSQLt.FakeTable e 
      tSQLt.SpyProcedure
  - Insieme con inserti di dati pertinenti.
  - Per ulteriori informazioni, vedere http://tsqlt.org/user-guide/isolating~~V - 
      dipendenze /
  
  - Atto
  - Eseguire il codice sotto test come una stored procedure, una funzione o una vista
  - E catturare i risultati in variabili o tabelle.
  
  - Assert
  - Confrontare i valori previsti ed effettivi, o tSQLt.Fail chiamata in un IF 
      dichiarazione.  
  - Disponibile afferma: tSQLt.AssertEquals, tSQLt.AssertEqualsString, 
      tSQLt.AssertEqualsTable
  - Per un elenco completo, vedere: http://tsqlt.org/user-guide/assertions/
  EXEC tSQLt . Fail 'TODO: Implementare questo test.'
  
END ;
Questo dovrebbe essere abbastanza familiare a coloro che hanno trascorso un po 'di tempo a scrivere i test prima, abbiamo il classico organizzare (o di "assemblare" in questo caso), atto, affermano modello e, naturalmente, è impostato a fallire perché non è ancora fare qualcosa.Naturalmente prima di poter fare qualsiasi cosa abbiamo bisogno di qualcosa per farlo funzionare in modo contro la facciamo solo creare una nuova funzione di valore scalare che non fa altro che dichiara i parametri corretti e resi nulli.
ALTER
)
RETURNS bit
AS
BEGIN
  EXEC tSQLt . Fail
   RETURN NULL
 END
Non sono convinto che chiamare tSQLt . Fail è davvero la cosa più intelligente da fare qui, ma ovviamente una sorta di eccezione deve essere gettato (in NotImplementedException pensiero. NET), e non è possibile RaiseError in una funzione. In ogni caso, è solo temporanea in modo che possiamo avere i nostri test scritto e francamente mi sono più interessato a far funzionare le cose più risucchiato in quel dibattito unit testing religiosa ho accennato in precedenza. Ecco il primo test semplice scriverò fare in modo che se tutto è null allora il risultato è nullo:
ALTER PROCEDURE [AspNetSiteTests] . [test nessuna intestazione restituisce null]
 AS
BEGIN

  - Montare
   DECLARE @ Server NVARCHAR ( 250 ) = NULL;
   DECLARE @ XAspNetVersion nvarchar ( 50 ) = NULL;
   DECLARE @ XAspNetMvcVersion nvarchar ( 50 ) = NULL;
   DECLARE @ XPoweredBy nvarchar ( 300 ) = NULL;
  
  --Act
  DECLARE @IsAspNetSite BIT;
  SET @IsAspNetSite = dbo.IsAspNetWebsite(@Server, @XAspNetVersion, 
      @XAspNetMvcVersion, @XPoweredBy);
  
  - Assert
   EXEC tSQLt . assertEquals NULL, @ IsAspNetSite ;
  
END ;
Ora possiamo andare avanti ed eseguire questo nel test runner:
Un test non avendo scritto e eseguito in test runner
Ottimo, questo è esattamente il tipo di flusso di lavoro ci si aspetterebbe quando si scrivono i test prima di nuovo in Visual Studio. Facciamo scrivere il resto di loro prima di poter realmente attuare la funzione di:
Otto le prove scritta e in mancanza di esecuzione in test runner
Ora possiamo andare avanti con l'effettiva implementazione del metodo e passare attraverso l'intero rosso, verde, ciclo di refactoring. Come ho iniziato ad attuare la funzione, mi salta al test runner, dare un vortice e guardare le prove a poco a poco iniziano a passare:
A poco a poco le prove che fanno passare il test runner
E naturalmente c'è qualche prolissità sul motivo per cui le cose vanno male, una volta drill-down dei messaggi di prova SQL:
La mancanza di test di uscita finestra di notifica
E questo è davvero - mantenere attuazione test e fare le cose verde, proprio come si farebbe indietro nel buon vecchio di Visual Studio.

Ma aspettate - c'è di più!

Mentre io non avevo bisogno di approfondire questa area solo per scrivere test contro una funzione semplice, Test SQL ha un supporto eccellente per affrontare la volatilità dei dati. Mi spiego: ci sono molti usi programmatici di TSQL che hanno una dipendenza dello stato dei dati. Ad esempio, una procedura stored viene eseguito su un tavolo e fa calcoli basati sui dati che è in là.
La sfida qui è in qualche modo simile a quello che abbiamo affrontato per molti anni durante la scrittura di unit test in Visual Studio in che quando le prove diventano dipendenti sullo stato dei dati si corre il rischio reale dei dati, non essere sempre in attesa che stato. Inoltre alla fine di dover pulire dopo voi stessi e cercando di ottenere tutti i dati in uno stato piacevole prevedibile prima di eseguire i test più. E 'un campo minato.
Il modo in cui SQL gestisce questo test è quello di consentire la creazione di tabelle falsi impalamento, che tutti gli attributi della cosa reale e consentono di pasticciare con essa il desiderio del vostro cuore senza modificare i dati persistenti. È quindi possibile affermare che la tabella corrisponde a un falso pre-stato definito previsto. Il modo migliore per ottenere la testa intorno a questo è quello di dare un'occhiata al video introduttivo Red Gate dove Grant Fritchey ti guida attraverso di essa (tabelle finte sono disponibili in tutto il marchio di 5 minuti):
Un'altra risorsa è il degno Simple-Talk articolo sulla base di test di prova di database di SQL Unità con TeamCity Continuous Integration . Sono stato un fan di integrazione degli strumenti di cancello rosso con TeamCity in passato, quindi questo si allinea molto al mio modo di pensare.

Riassunto

Come tutti gli altri bit cancello rosso, quello che mi piace di test SQL è che è estremamente pratico e si integra perfettamente nel vostro modo di lavorare durante la creazione di banche dati; è proprio lì in SSMS ed è molto facilmente accessibile. Non ci sono fumo e specchi o la magia in corso in background, è molto facile vedere esattamente come la cosa è mettere insieme e quello che sta facendo sotto le coperte.
Test di SQL ha un senso per tutti i motivi stessi che l'unità di prova i vostri progetti di Visual Studio fa, avere la certezza che il codice sta facendo ciò che si intende oggi e in futuro è assolutamente inestimabile. Inoltre è possibile eliminare il tutto in controllo del codice sorgente SQL e condividere i test con il team quindi escludere quando si genera script per il cambio e la pubblicazione via SQL Confronta. Nizza.
Io non sono molto sicuro della roadmap futura Red Gate per il prodotto, ma soprattutto mentre è gratis dico entrare e mettere le mani su di esso. Avevo tutto attivo e funzionante con i miei propri test al letteralmente circa 20 minuti - hanno a go!

Nessun commento:

Posta un commento