Denne artikel giver en gennemgang af databaseenhed, der tester en lagret procedure, som indeholder en hjælpeprocedure i den.
I denne artikel vil jeg diskutere et databaseenhedstestscenario, når en lagret hovedprocedure afhænger af en hjælpeprocedure, og hovedproceduren skal enhedstestes for at sikre, at kravene er opfyldt. Nøglen er at sikre, at en enhedstest kun kan skrives for en enkelt kodeenhed, hvilket betyder, at vi har brug for én enhedstest til hovedproceduren og en anden enhedstest til brugsproceduren.
Enhedstest af en enkelt lagret procedure er lettere sammenlignet med enhedstest af en procedure, der kalder en hjælpeprocedure inde i sin kode.
Det er meget vigtigt at forstå scenariet for hjælpeprocedurer, og hvorfor det er anderledes end enhedstest af en normal lagret procedure.
Scenarie:Hjælpeprocedure inden for hovedprocedure
For at forstå værktøjsprocedurescenariet lad os begynde med definitionen og eksemplet på værktøjsproceduren:
Hvad er hjælpeprocedure
En hjælpeprocedure er generelt en lille procedure, som bruges af hovedproceduren(erne) til at udføre en bestemt opgave, såsom at få noget til hovedproceduren eller tilføje noget til hovedproceduren.
En anden definition af hjælpeprocedure er en lille lagret procedure skrevet til vedligeholdelsesformål, som kan involvere systemtabeller eller visninger, der skal kaldes af et vilkårligt antal procedurer eller endda direkte.
Eksempler på hjælpeprocedurer
Tænk på et kunde-ordre-produkt-scenarie, hvor en kunde afgiver en ordre på et bestemt produkt. Hvis vi opretter hovedproceduren for at få os alle ordrer afgivet af en bestemt kunde, kan en hjælpeprocedure bruges til at hjælpe os med at forstå, om hver ordre blev afgivet af kunden på hverdage eller weekender.
På denne måde kan en lille hjælpeprocedure kan skrives for at returnere "Weekday" eller "Weekend" baseret på den dato, produktet blev bestilt af kunden.
Et andet eksempel kan være systemlagrede procedurer såsom "sp_server_info" i masterdatabasen, som giver SQL Server installeret versionsinformation:
EXEC sys.sp_server_info
Hvorfor enhedstestværktøjsproceduren er anderledes
Som diskuteret tidligere er enhedstestning af en hjælpeprocedure, som kaldes inde i hovedproceduren, lidt kompliceret end enhedstestning af en simpel lagret procedure.
I betragtning af kunde-ordre-produkt-eksemplet nævnt ovenfor, er vi nødt til at skrive en enhedstest for at kontrollere, at værktøjsproceduren fungerer fint, og der skal også skrives en enhedstest for at kontrollere, at hovedproceduren, som kalder værktøjsproceduren også fungerer korrekt, samt opfylder forretningskravene.
Dette er illustreret som følger:
Isolering fra Utility/Main Procedure Challenge
Hovedudfordringen ved at skrive en enhedstest(er) for proceduren, der involverer en brugsprocedure, er at sikre, at vi ikke skal bekymre os om, hvordan brugsproceduren fungerer, når vi skriver en enhedstest for hovedproceduren, og det samme gælder for brugsproceduren. . Dette er en udfordrende opgave, som man skal huske på, mens man skriver enhedstests til et sådant scenarie.
Isolering fra værktøjet eller hovedproceduren er et must, afhængigt af hvilken procedure der testes. Vi skal huske på følgende ting i forbindelse med isolering under enhedstestning:
- Isolering fra hjælpeproceduren ved enhedstest af hovedproceduren.
- Isolering fra hovedproceduren ved enhedstest af hjælpeprogram.
Husk venligst, at denne artikel fokuserer på enhedstest af hovedproceduren ved at isolere den fra dens hjælpeprocedure.
Oprettelse af hovedprocedure og dens værktøjsprocedure
For at kunne skrive en enhedstest for et scenarie, hvor hjælpeproceduren er i brug af hovedproceduren, skal vi først have følgende forudsætninger:
- Eksempeldatabase
- Forretningskrav
Opsætning af prøvedatabase (SQLBookShop)
Vi er ved at oprette en simpel prøvedatabase med to tabeller kaldet "SQLBookShop", som indeholder registreringerne af alle de bøger, der er bestilt som vist nedenfor:
Opret SQLBookShop-eksempeldatabase som følger:
-- (1) Create SQLBookShop database CREATE DATABASE SQLBookShop; GO
Opret og udfyld databaseobjekter (tabeller) som følger:
USE SQLBookShop; -- (2) Drop book and book order tables if they already exist IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_NAME='BookOrder') DROP TABLE dbo.BookOrder IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_NAME='Book') DROP TABLE dbo.Book IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES T WHERE T.TABLE_TYPE='View' AND t.TABLE_NAME='OrderedBooks') DROP VIEW dbo.OrderedBooks -- (3) Create book table CREATE TABLE Book (BookId INT PRIMARY KEY IDENTITY(1,1), Title VARCHAR(50), Stock INT, Price DECIMAL(10,2), Notes VARCHAR(200) ) -- (4) Create book order table CREATE TABLE dbo.BookOrder (OrderId INT PRIMARY KEY IDENTITY(1,1), OrderDate DATETIME2, BookId INT, Quantity INT, TotalPrice DECIMAL(10,2) ) -- (5) Adding foreign keys for author and article category ALTER TABLE dbo.BookOrder ADD CONSTRAINT FK_Book_BookId FOREIGN KEY (BookId) REFERENCES Book (BookId) -- (6) Populaing book table INSERT INTO dbo.Book (Title, Stock, Price, Notes) VALUES ('Mastering T-SQL in 30 Days', 10, 200, ''), ('SQL Database Reporting Fundamentals', 5, 100, ''), ('Common SQL Mistakes by Developers',15,100,''), ('Optimising SQL Queries',20,200,''), ('Database Development and Testing Tips',30,50,''), ('Test-Driven Database Development (TDDD)',20,200,'') -- (7) Populating book order table INSERT INTO dbo.BookOrder (OrderDate, BookId, Quantity, TotalPrice) VALUES ('2018-01-01', 1, 2, 400), ('2018-01-02', 2, 2, 200), ('2018-01-03', 3, 2, 200), ('2018-02-04', 1, 2, 400), ('2018-02-05', 1, 3, 600), ('2018-02-06', 4, 3, 600), ('2018-03-07', 5, 2, 100), ('2018-03-08', 6, 2, 400), ('2018-04-10', 5, 2, 100), ('2018-04-11', 6, 3, 600); GO -- (8) Creating database view to see all the books ordered by customers CREATE VIEW dbo.OrderedBooks AS SELECT bo.OrderId ,bo.OrderDate ,b.Title ,bo.Quantity ,bo.TotalPrice FROM BookOrder bo INNER JOIN Book b ON bo.BookId = b.BookId
Hurtigt tjek – Eksempeldatabase
Foretag et hurtigt databasetjek ved at køre OrderedBooks-visningen ved hjælp af følgende kode:
USE SQLBookShop -- Run OrderedBooks view SELECT ob.OrderID ,ob.OrderDate ,ob.Title AS BookTitle ,ob.Quantity ,ob.TotalPrice FROM dbo.OrderedBooks ob
Bemærk venligst, at jeg bruger dbForge Studio til SQL Server, så output-looket kan variere, hvis du kører den samme kode i SSMS (SQL Server Management Studio). Der er dog ingen forskel mellem scripts og deres resultater.
Forretningskrav for at se den seneste ordre med yderligere oplysninger
Et forretningskrav er blevet sendt til udviklerteamet, som siger, at "Slutbrugeren ønsker at vide om den seneste ordre afgivet for en bestemt bog sammen med oplysningerne om, hvorvidt ordren blev afgivet på en hverdag eller weekend"
Et ord om TDDD
Vi følger ikke strengt testdrevet databaseudvikling (TDDD) i denne artikel, men jeg anbefaler på det kraftigste at bruge testdrevet databaseudvikling (TDDD) til at skabe både hoved- og hjælpeprocedurer, som begynder med at oprette en enhedstest for at kontrollere, om der findes et objekt, som fejler først, efterfulgt af oprettelse af objektet og genkørsel af enhedstesten, som skal bestå.
For en detaljeret gennemgang, se venligst den første del af denne artikel.
Procedure for identificering af hjælpeprogrammer
Når vi ser forretningskravet, er én ting sikker, vi har brug for en hjælpeprocedure, der kan fortælle os, om en bestemt dato er en hverdag eller en weekend.
Oprettelse af værktøjsprocedure (GetDayType)
Opret en hjælpeprocedure og kald den "GetDayType" som følger:
-- Creating utility procedure to check whether the date passed to it is a weekday or weekend CREATE PROCEDURE dbo.uspGetDayType @OrderDate DATETIME2,@DayType CHAR(7) OUT AS BEGIN SET NOCOUNT ON IF (SELECT DATENAME(WEEKDAY, @OrderDate)) = 'Saturday' OR (SELECT DATENAME(WEEKDAY, @OrderDate)) = 'Sunday' SELECT @DayType= 'Weekend' ELSE SELECT @DayType = 'Weekday' SET NOCOUNT OFF END GO
Hurtig tjek – hjælpeprocedure
Skriv følgende linjer med kode for hurtigt at tjekke hjælpeproceduren:
-- Quick check utility procedure declare @DayType varchar(10) EXEC uspGetDayType '20181001',@DayType output select @DayType AS [Type of Day]
Oprettelse af hovedprocedure (GetLatestOrderByBookId)
Opret hovedproceduren for at se den seneste ordre afgivet for en bestemt bog, og også om ordren blev afgivet på en hverdag eller weekend, og kald den "GetLatestOrderByBookId", som indeholder opfordringen til værktøjsproceduren som følger:
-- Creating stored procedure to get most recent order based on bookid and also whether order was placed on weekend or weekday CREATE PROCEDURE dbo.uspGetLatestOrderByBookId @BookId INT AS BEGIN -- Declare variables to store values DECLARE @OrderId INT ,@Book VARCHAR(50) ,@OrderDate DATETIME2 ,@Quantity INT ,@TotalPrice DECIMAL(10, 2) ,@DayType VARCHAR(10) -- Get most recent order for a particular book and initialise variables SELECT TOP 1 @OrderId = bo.OrderId ,@Book = b.Title ,@OrderDate = bo.OrderDate ,@Quantity = bo.Quantity ,@TotalPrice = bo.TotalPrice FROM BookOrder bo INNER JOIN Book b ON bo.BookId = b.BookId WHERE bo.BookId = @BookId ORDER BY OrderDate DESC -- Call utility procedure to get type of day for the above selected most recent order EXEC uspGetDayType @OrderDate ,@DayType OUTPUT -- Show most recent order for a particular book along with the information whether order was placed on weekday or weekend SELECT @OrderId AS OrderId ,@OrderDate AS OrderDate ,@Book AS Book ,@Quantity AS Quantity ,@TotalPrice AS TotalPrice ,@DayType AS DayType END GO
Hurtig tjek – Hovedprocedure
Kør følgende kode for at se, om proceduren fungerer fint eller ej:
-- Get latest order for the bookid=6 EXEC uspGetLatestOrderByBookId @BookId = 6
Hovedprocedure for enhedstestning af opkaldsværktøj
Nøglen her er at forstå forskellen mellem enhedstest af hovedproceduren og hjælpeproceduren.
Vi er i øjeblikket fokuseret på enhedstest af hovedproceduren, så det betyder, at værktøjsproceduren skal isoleres elegant fra denne enhedstest.
Brug af spionprocedure
For at sikre, at hovedprocedureenhedstesten forbliver fokuseret på at teste funktionaliteten af hovedproceduren, er vi nødt til at bruge spionproceduren leveret af tSQLt, som vil fungere som en stub (pladsholder) for værktøjsproceduren.
Ifølge tsqlt.org skal du huske, at hvis du udspionerer en procedure, er du faktisk ikke enhedsteste den procedure, men du gør det lettere for den anden procedure, der er relateret til den procedure, du spionerer, at blive enhedstestet.
For eksempel, i vores tilfælde, hvis vi ønsker at enhedsteste hovedproceduren, så er vi nødt til at håne hjælpeproceduren ved at bruge spionproceduren, som vil gøre det nemmere for os at enhedsteste hovedproceduren.
Oprettelse af enhedstest for hovedprocedure for spionværktøj
Opret en databaseenhedstest for at kontrollere, at hovedproceduren fungerer korrekt.
Denne artikel fungerer for dbForge Studio til SQL Server (eller kun dbForge Unit Test) og SSMS (SQL Server Management Studio) . Bemærk dog, at når du bruger SSMS (SQL Server Management Studio), antager jeg, at du allerede har installeret tSQLt Framework og klar til at skrive enhedstestene.
For at oprette den første databaseenhedstest skal du højreklikke på SQLBookShop-databasen. På genvejsmenuen skal du klikke på Unit Test og derefter Tilføj ny test som følger:
Skriv enhedstestkoden:
CREATE PROCEDURE GetLatestOrder.[test to check uspGetLatestOrderByBookId outputs correct data] AS BEGIN --Assemble -- Mock order Book and BookOrder table EXEC tSQLt.FakeTable @TableName='dbo.Book' EXEC tSQLt.FakeTable @TableName='dbo.BookOrder' -- Adding mock data to book table INSERT INTO dbo.Book (BookId,Title, Stock, Price, Notes) VALUES (1,'Basics of T-SQL Programming', 10, 100, ''), (2,'Advanced T-SQL Programming', 10, 200, '') -- Adding mock data to bookorder table INSERT INTO dbo.BookOrder (OrderId,OrderDate, BookId, Quantity, TotalPrice) VALUES (1,'2018-01-01', 1, 2, 200), (2,'2018-05-01', 1, 2, 200), (3,'2018-07-01', 2, 2, 400) -- Creating expected table CREATE TABLE GetLatestOrder.Expected ( OrderId INT ,OrderDate DATETIME2 ,Book VARCHAR(50) ,Quantity INT ,TotalPrice DECIMAL(10, 2) ,DayType VARCHAR(10) ) -- Creating actual table CREATE TABLE GetLatestOrder.Actual ( OrderId INT ,OrderDate DATETIME2 ,Book VARCHAR(50) ,Quantity INT ,TotalPrice DECIMAL(10, 2) ,DayType VARCHAR(10) ) -- Creating uspGetDayType spy procedure to isolate main procedure from it so that main procedure can be unit tested EXEC tSQLt.SpyProcedure @ProcedureName = 'dbo.uspGetDayType',@CommandToExecute = 'set @DayType = ''Weekday'' ' -- Inserting expected values to the expected table INSERT INTO GetLatestOrder.Expected (OrderId, OrderDate, Book, Quantity, TotalPrice, DayType) VALUES (2,'2018-05-01', 'Basics of T-SQL Programming', 2, 200,'Weekday'); --Act INSERT INTO GetLatestOrder.Actual EXEC uspGetLatestOrderByBookId @BookId = 1 -- Calling the main procedure --Assert --Compare expected results with actual table results EXEC tSQLt.AssertEqualsTable @Expected = N'GetLatestOrder.Expected', -- nvarchar(max) @Actual = N'GetLatestOrder.Actual' -- nvarchar(max) END; GO
Kørsel af enhedstest for hovedprocedure
Kør enhedstesten:
Tillykke, du har med succes enhedstestet en lagret procedure ved at isolere den fra dens hjælpeprocedure efter brug af spionprocedure.
For mere information om enhedstestning bedes du gennemgå følgende dele af min tidligere artikel om testdrevet databaseudvikling (TDDD):
- Gå til Start Test-Driven Database Development (TDDD) – Del 1
- Hop til Start Test-Driven Database Development (TDDD) – Del 2
- Hop til Start Test-Driven Database Development (TDDD) – Del 3
Ting at gøre
Du kan nu oprette databaseenhedstest til lidt komplekse scenarier, hvor lagrede procedurer kalder hjælpeprocedurer.
- Prøv venligst at ændre spionproceduren @CommandToExecute argument (værdi) som @CommandToExecute ='set @DayType ="Intet" ' og se, at testen vil mislykkes nu
- Prøv venligst at opfylde forretningskravet i denne artikel ved at bruge testdrevet databaseudvikling (TDDD)
- Prøv venligst at opfylde et andet forretningskrav for at se den seneste ordre afgivet af enhver kunde, der bruger testdrevet udvikling (TDDD), der involverer den samme hjælpeprocedure
- Prøv venligst at oprette en enhedstest for hjælpeproceduren ved at isolere hovedproceduren
- Prøv dig selv at oprette en enhedstest for en procedure, der kalder to hjælpeprocedurer
Nyttigt værktøj:
dbForge Unit Test – en intuitiv og praktisk GUI til implementering af automatiseret enhedstest i SQL Server Management Studio.