Proiectează și implementează o strategie de testare
Un proiect de bază de date SQL care se construiește cu succes nu înseamnă că procedurile stocate din el returnează rezultatele corecte. O procedură poate compila fără erori și totuși poate calcula totalurile greșite sau poate sări peste o verificare de validare. Testarea detectează aceste probleme înainte ca acestea să ajungă în producție.
Înțelege nivelurile de testare a bazelor de date
Testarea bazelor de date funcționează pe straturi, fiecare detectând o clasă diferită de problemă:
-
Validarea construcției este pasul
dotnet buildpe care îl ai deja. Detectează erori de sintaxă și referințe la obiecte defecte. Rapid, dar doar dovedește că schema este valabilă din punct de vedere structural. - Testele unitare verifică că procedurile și funcțiile stocate individuale produc rezultatele corecte pentru un anumit set de intrări. Detectează erori logice.
- Testele de integrare exersează scenarii end-to-end pe o bază de date implementată. Ele demonstrează că obiectele funcționează corect împreună, dar necesită o instanță de rulare și necesită cel mai mult timp.
Fiecare strat este mai lent și mai scump decât cel anterior, dar detectează și probleme pe care stratul anterior nu le poate detecta.
Creează teste unitare SQL Server
SQL Server Data Tools (SSDT) în Visual Studio include un cadru integrat pentru testele unitare ale bazei de date. Fiecare test execută T-SQL pe o bază de date activă și validează rezultatele folosind condiții de testare.
Structura unui test unitar
Fiecare test are trei secțiuni care urmează un model setup-execute-cleanup:
- Pre-test: setează datele de care testul are nevoie. Inserează înregistrările clienților, șterge datele rămase din rundele anterioare.
- Test: execută operațiunea pe care o testezi. Cheamă procedura stocată și interogează vizualizarea.
- Post-test: curăță după test ca să nu contamineze următoarea încercare.
Condiții de testare
După rularea testului T-SQL, condițiile de testare validează ce a revenit. Cele mai frecvent utilizate condiții sunt:
- Număr de rânduri: verifică dacă setul de rezultate conține numărul așteptat de rânduri.
- Valoare scalară: verifică că o celulă specifică din setul de rezultate conține valoarea așteptată.
- Schema așteptată: verifică dacă setul de rezultate conține numele de coloane și tipurile de date așteptate.
Alte condiții încorporate includ Data Checksum, ResultSet Gol, RezultatSetul Nevid și Timpul de Execuție.
Creează un proiect de testare unitară
Configurarea testelor unitare SQL Server în Visual Studio necesită câțiva pași:
- Deschide-ți proiectul de bază de date SQL.
- În SQL Server Object Explorer, găsește procedura stocată sau funcția pe care vrei să o testezi.
- Faceți clic dreapta pe obiect și selectați Create Unit Tests.
- Alege sau creează un proiect de test C#.
- Setează conexiunea de test la baza ta de date de dezvoltare.
- Selectează Implementează automat proiectul bazei de date înainte de a rula testele unitare. Această opțiune menține baza de date de testare sincronizată cu cele mai recente modificări ale proiectului tău.
Designerul începe cu un șablon T-SQL în care scrii logica de test și atașezi condiții de testare.
Scrierea testelor unitare eficiente de baze de date
Un test unitar bun răspunde la o întrebare specifică: "Această procedură face ceea ce ar trebui să facă pentru o intrare cunoscută?" Iată un exemplu care testează uspPlaceNewOrder, verificând dacă plasarea corectă a comenzii actualizează totalul clientului de la începutul anului:
-- Pre-test: Set up customer and clear previous data
DECLARE @CustomerID INT;
INSERT INTO [Sales].[Customer] (CustomerName) VALUES (N'Test Customer');
SET @CustomerID = SCOPE_IDENTITY();
DELETE FROM [Sales].[Orders] WHERE [CustomerID] = @CustomerID;
-- Test: Place an order and verify YTDOrders updated correctly
DECLARE @RC INT;
EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 100, GETDATE(), 'O';
SELECT [YTDOrders]
FROM [Sales].[Customer]
WHERE [CustomerID] = @CustomerID;
📝 Combinați acest test T-SQL cu o condiție de test Scalar Value care se așteaptă YTDOrders ca valoarea să fie 100.
Teste negative
De asemenea, trebuie să verifici dacă procedurile stocate eșuează corect atunci când primesc intrări invalide. De exemplu, anularea unei comenzi deja expediate ar trebui să genereze o eroare, nu să reușească în tăcere. Un test negativ confirmă că eroarea așteptată apare.
Când selectați Create Unit Tests în pasul 3 al secțiunii anterioare, Visual Studio generează un proiect de testare C# în Solution Explorer cu un .cs fișier care conține un test pentru fiecare procedură stocată pe care ați selectat-o. De exemplu, dacă ai creat un test pentru uspCancelOrder, fișierul generat include o secțiune numită Sales_uspCancelOrder_Test. Pentru a marca acel test ca test negativ, deschide fișierul .cs în Solution Explorer și adaugă atributul ExpectedSqlException direct deasupra lui și salvează fișierul:
[TestMethod()]
[ExpectedSqlException(Severity = 16, MatchFirstError = false, State = 1)]
public void Sales_uspCancelOrder_FilledOrder_Test()
Testul trece doar atunci când procedura stocată generează o eroare care corespunde severității și stării specificate. Dacă procedura reușește în liniște, testul eșuează, exact ceea ce îți dorești.
Proiectează o abordare de testare a integrării
Testele unitare izolează obiecte individuale. Testele de integrare merg mai departe și testează scenarii care acoperă mai multe operațiuni. Ei răspund la întrebări precum:
- O secvență de apeluri de procedură stocată lasă baza de date în starea așteptată?
- Declanșatoarele se activează corect când datele ajung prin stratul aplicației?
- Vizualizările returnează rezultate corecte după o serie de modificări conexe ale tabelelor?
Testele de integrare necesită o bază de date dedicată. Implementează proiectul bazei de date SQL într-o instanță de test înainte de fiecare rulare folosind setarea Implementează automat proiectul bazei de date înainte de rularea testelor unitare . Această setare menține schema de testare actualizată.
Considerații pentru bazele de date de testare
Atât testele unitare, cât și cele de integrare rulează T-SQL pe o bază de date activă, așa că mediul de testare necesită o configurare atentă pentru a produce rezultate fiabile.
- Izolați testele din producție. Folosește o instanță separată sau o bază de date dedicată de testare. Testarea în raport cu producția nu este niciodată recomandată.
- Resetează la o stare cunoscută înainte de fiecare rundă. Scripturile post-implementare sau scripturile de curățare a testelor rezolvă această problemă.
- Externalizează șirurile de conexiune din fișierele de configurare astfel încât pipeline-urile locale de dezvoltare și CI să indice fiecare baza de date corectă fără modificări de cod.
Integrarea testelor în pipeline-urile CI/CD
Adaugă un pas de test după build și implementare, astfel încât testele să ruleze automat la fiecare commit. În Azure DevOps, folosește sarcina VSTest :
- task: VSTest@2
inputs:
testAssembly: '**\*Tests.dll'
searchFolder: '$(System.DefaultWorkingDirectory)'
În GitHub Actions, rulează testele folosind dotnet test:
- name: Run database unit tests
run: dotnet test ./DatabaseTests/DatabaseTests.csproj
Sfat
Configurează proiectul de testare să implementeze automat proiectul bazei de date înainte de rularea testelor. Această setare asigură că schema bazei de date de testare corespunde proiectului la momentul testării.
Când un test eșuează, pipeline-ul se oprește și schimbarea nu ajunge la staging sau producție. Această întârziere oferă echipei timp să rezolve problema înainte ca aceasta să afecteze orice mediu.
Principalele concluzii
Testarea bazei de date acoperă trei niveluri: validarea construcției pentru corectitudinea structurală, teste unitare pentru verificarea logică și teste de integrare pentru fluxuri de lucru end-to-end. Testele unitare SQL Server urmează o structură în trei faze: preacțiuni de testare, acțiuni de test și post-acțiuni de testare. Pentru a verifica comportamentul procedurilor stocate și al funcției, folosiți condiții de test precum Scalar Value, Row Count, și Expected Schema. Pentru a testa metode care ar trebui să valideze căile de gestionare a erorilor, adaugă atributul ExpectedSqlException . Conectează proiectele de testare în pipeline-ul tău CI/CD astfel încât un test eșuat să blocheze implementarea înainte ca modificările să ajungă la staging sau producție. Împreună, aceste trei straturi formează o plasă de siguranță care permite echipei tale să implementeze modificările bazei de date cu încredere, nu cu anxietate.