Тази статия предоставя пояснение за тестване на единица база данни на съхранена процедура, която съдържа процедура за помощ в нея.
В тази статия ще обсъдя един сценарий за тестване на база данни, когато основната съхранена процедура зависи от процедура на помощна програма и основната процедура трябва да бъде тествана на модул, за да се уверим, че изискванията са изпълнени. Ключът е да се гарантира, че единичен тест може да бъде написан само за една единица код, което означава, че се нуждаем от един единичен тест за основната процедура и друг единичен тест за процедурата на помощната програма.
Модулното тестване на една съхранена процедура е по-лесно в сравнение с модулното тестване на процедура, която извиква процедура на помощна програма в кода си.
Много е важно да разберете сценария на процедурата за помощна програма и защо той е различен от тестването с модул на нормална съхранена процедура.
Сценарий:Полезна процедура в рамките на основната процедура
За да разберем сценария на полезна процедура, нека започнем с дефиницията и примера за процедурата за помощна програма:
Какво е процедура за помощна програма
Помощната процедура обикновено е малка процедура, която се използва от главната(ите) процедура(и) за извършване на някаква специфична задача, като например получаване на нещо за основната процедура или добавяне на нещо към основната процедура.
Друга дефиниция на процедура за помощ е малка съхранена процедура, написана за целите на поддръжката, която може да включва системни таблици или изгледи, които да бъдат извиквани от произволен брой процедури или дори директно.
Примери за полезни процедури
Помислете за сценарий клиент-поръчка-продукт, при който клиент прави поръчка за конкретен продукт. Ако създадем основната процедура, за да получим всички поръчки, направени от конкретен клиент, тогава може да се използва процедура за помощ, за да ни помогне да разберем дали всяка поръчка е била направена от клиента в делничен ден или уикенд.
По този начин а малка помощна процедура може да бъде написана, за да върне „Ден от седмицата“ или „Уикенд“ въз основа на датата, на която продуктът е поръчан от клиента.
Друг пример могат да бъдат системно съхранени процедури като “sp_server_info” в главната база данни, която дава информация за инсталираната версия на SQL Server:
EXEC sys.sp_server_info
Защо процедурата на помощната програма за тестване на модул е различна
Както беше обсъдено по-рано, модулното тестване на помощна процедура, която се извиква в основната процедура, е леко сложна от тестването на модул на проста съхранена процедура.
Като се има предвид споменатият по-горе пример за продукт за поръчка на клиента, трябва да напишем единичен тест, за да проверим, че процедурата за помощ работи добре, а също така трябва да бъде написан единичен тест, за да проверим, че основната процедура, която извиква помощната процедура, също функционира правилно, както и отговаря бизнес изискването(ите).
Това е илюстрирано по следния начин:
Изолиране от предизвикателство за помощна програма/главна процедура
Основното предизвикателство при написването на единичен тест(и) за процедурата, която включва процедура за помощ, е да се уверим, че не трябва да се притесняваме за функционирането на процедурата за помощ, когато пишем единичен тест за основната процедура и същото важи и за процедурата за полезност . Това е предизвикателна задача, която трябва да се има предвид при писане на единични тестове за такъв сценарий.
Изолирането от помощната програма или основната процедура е задължително, в зависимост от това коя процедура се тества. Трябва да имаме предвид следните неща в контекста на изолирането по време на тестване на модули:
- Изолиране от процедурата за помощна програма, когато модулното тестване на основната процедура.
- Изолиране от основната процедура при помощна процедура за тестване на модул.
Моля, не забравяйте, че тази статия е фокусирана върху модулното тестване на основната процедура, като я изолира от нейната полезна процедура.
Създаване на основна процедура и нейната помощна процедура
За да напишем единичен тест за сценарий, при който помощната процедура се използва от основната процедура, първо трябва да имаме следните предпоставки:
- Примерна база данни
- Бизнес изискване/и
Настройте примерна база данни (SQLBookShop)
Създаваме проста примерна база данни с две таблици, наречена „SQLBookShop“, която съдържа записите на всички подредени книги, както е показано по-долу:
Създайте примерна база данни на SQLBookShop, както следва:
-- (1) Create SQLBookShop database CREATE DATABASE SQLBookShop; GO
Създайте и попълнете обекти на база данни (таблици), както следва:
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
Бърза проверка – Примерна база данни
Направете бърза проверка на базата данни, като стартирате изгледа OrderedBooks, като използвате следния код:
USE SQLBookShop -- Run OrderedBooks view SELECT ob.OrderID ,ob.OrderDate ,ob.Title AS BookTitle ,ob.Quantity ,ob.TotalPrice FROM dbo.OrderedBooks ob
Моля, имайте предвид, че използвам dbForge Studio за SQL Server, така че изходният вид може да се различава, ако стартирате същия код в SSMS (SQL Server Management Studio). Въпреки това, няма разлика между скриптовете и техните резултати.
Бизнес изискване да видите последната поръчка с допълнителна информация
На екипа на разработчиците е изпратено бизнес изискване, което гласи, че „Крайният потребител иска да знае за последната поръчка, направена за конкретна книга, заедно с информацията дали поръчката е направена в делничен ден или уикенд“
Една дума за TDDD
Ние не следваме стриктно разработване на база данни, управлявано от тестове (TDDD) в тази статия, но силно препоръчвам да използвате разработване на база данни, управлявано от тестове (TDDD), за създаване на основни и помощни процедури, което започва със създаване на единичен тест, за да провери дали съществува обект, който отначало се проваля, последвано от създаване на обекта и повторно изпълнение на единичния тест, който трябва да премине.
За подробен преглед, моля, вижте първата част на тази статия.
Идентифициране на помощна процедура
Виждайки бизнес изискването, едно нещо е сигурно, че имаме нужда от процедура за помощ, която може да ни каже дали определена дата е делничен ден или уикенд.
Създаване на помощна процедура (GetDayType)
Създайте процедура за помощна програма и я наречете „GetDayType“, както следва:
-- 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
Бърза проверка – Процедура за помощна програма
Напишете следните редове код, за да проверите бързо помощната процедура:
-- Quick check utility procedure declare @DayType varchar(10) EXEC uspGetDayType '20181001',@DayType output select @DayType AS [Type of Day]
Създаване на основна процедура (GetLatestOrderByBookId)
Създайте основната процедура, за да видите най-новата поръчка, направена за конкретна книга, както и дали поръчката е направена в делничен ден или уикенд и я наречете „GetLatestOrderByBookId“, която съдържа извикването на процедурата за помощ, както следва:
-- 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
Бърза проверка – Основна процедура
Изпълнете следния код, за да видите дали процедурата работи добре или не:
-- Get latest order for the bookid=6 EXEC uspGetLatestOrderByBookId @BookId = 6
Основна процедура за тестване на модули Извикване на процедура на помощна програма
Ключът тук е да се разбере разликата между тестването на модула на основната процедура и процедурата на помощната програма.
Понастоящем сме фокусирани върху модулното тестване на основната процедура, така че това означава, че помощната процедура трябва да бъде изящно изолирана от този модулен тест.
Използване на шпионска процедура
За да се уверим, че единичният тест на основната процедура остава фокусиран върху тестването на функционалността на основната процедура, трябва да използваме шпионска процедура, предоставена от tSQLt, която ще действа като заглушка (заместител) за помощната процедура.
Според tsqlt.org, моля, не забравяйте, че ако шпионирате процедура, вие всъщност не тествате тази процедура, а улеснявате другата процедура, свързана с процедурата, която шпионирате, да бъде тествана на модул.
Например, в нашия случай, ако искаме да тестваме модула на основната процедура, тогава трябва да се подиграем на процедурата за помощ, като използваме шпионска процедура, която ще ни улесни при единично тестване на основната процедура.
Създаване на единичен тест за главна процедура Процедура на помощната програма за шпиониране
Създайте един тест за база данни, за да проверите правилно функционирането на основната процедура.
Тази статия работи за dbForge Studio за SQL Server (или само за dbForge Unit Test) и SSMS (SQL Server Management Studio) . Въпреки това, моля, имайте предвид, че когато използвате SSMS (SQL Server Management Studio), предполагам, че вече сте инсталирали tSQLt Framework и сте готови да напишете модулните тестове.
За да създадете първия тест за единица база данни, щракнете с десния бутон върху базата данни SQLBookShop. В контекстното меню щракнете върху Единичен тест и след това Добавете нов тест, както следва:
Напишете кода на единичния тест:
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
Извършване на единичен тест за основна процедура
Изпълнете единичния тест:
Поздравления, успешно тествахте единично съхранена процедура, като я изолирате от нейната помощна процедура след използване на шпионска процедура.
За повече информация относно модулното тестване, моля, прегледайте следните части от предишната ми статия относно разработването на база данни, управлявана от тестове (TDDD):
- Прескочете към стартиране на разработване на база данни, управлявано от тестове (TDDD) – част 1
- Прескочете към стартиране на разработване на база данни, управлявано от тестове (TDDD) – част 2
- Прескочете към стартиране на разработване на база данни, управлявано от тестове (TDDD) – част 3
Неща за правене
Вече можете да създавате единични тестове на база данни за малко сложни сценарии, при които съхранените процедури извикват помощни процедури.
- Моля, опитайте да промените шпионска процедура @CommandToExecute аргумент (стойност) като @CommandToExecute =‘set @DayType =”Nothing” ‘ и вижте, че тестът ще се провали сега
- Моля, опитайте да изпълните бизнес изискването в тази статия, като използвате разработване на база данни, управлявано от тестове (TDDD)
- Моля, опитайте се да изпълните друго бизнес изискване, за да видите най-новата поръчка, направена от който и да е клиент, използвайки тестово управлявана разработка (TDDD), включваща същата процедура за помощ
- Моля, опитайте да създадете единичен тест за помощна процедура, като изолирате главната процедура
- Моля, опитайте да създадете единичен тест за процедура, която извиква две помощни процедури
Полезен инструмент:
dbForge Unit Test – интуитивен и удобен GUI за внедряване на автоматизирано тестване на модули в SQL Server Management Studio.