sql >> Databáze >  >> RDS >> Database

Zjednodušení testování jednotky Hlavní uložená procedura, která také nazývá proceduru utility

Tento článek poskytuje návod na testování databázové jednotky uložené procedury, která obsahuje proceduru obslužného programu.

V tomto článku budu diskutovat o scénáři testování databázové jednotky, kdy hlavní uložená procedura závisí na proceduře obslužného programu a hlavní procedura musí být testována na jednotku, aby se zajistilo, že jsou splněny požadavky. Klíčem je zajistit, aby jednotkový test mohl být zapsán pouze pro jednu jednotku kódu, což znamená, že potřebujeme jeden unit test pro hlavní proceduru a další unit test pro obslužnou proceduru.

Unit testování jedné uložené procedury je snazší ve srovnání s unit testováním procedury, která ve svém kódu volá obslužnou proceduru.

Je velmi důležité porozumět scénáři obslužné procedury a proč se liší od testování jednotky běžné uložené procedury.

Scénář:Obslužný postup v rámci hlavního postupu

Abychom porozuměli scénáři procedury utility, začněme definicí a příkladem procedury utility:

Co je to obslužný postup

Obslužná procedura je obecně malá procedura, kterou hlavní procedura(y) používá k provedení nějakého konkrétního úkolu, jako je získání něčeho pro hlavní proceduru nebo přidání něčeho do hlavní procedury.

Další definicí obslužné procedury je malá uložená procedura napsaná pro účely údržby, která může zahrnovat systémové tabulky nebo pohledy, které lze volat libovolným počtem procedur nebo dokonce přímo.

Příklady obslužného postupu

Představte si scénář zákazník-objednávka-produkt, kde zákazník zadá objednávku na konkrétní produkt. Pokud vytvoříme hlavní postup, abychom dostali všechny objednávky zadané konkrétním zákazníkem, pak lze použít obslužný postup, který nám pomůže pochopit, zda byla každá objednávka zadána zákazníkem ve všední den nebo o víkendu.
Tímto způsobem lze Procedura malého obslužného programu může být napsána tak, že vrátí „Den v týdnu“ nebo „Víkend“ na základě data, kdy si zákazník objednal produkt.

Dalším příkladem mohou být systémové uložené procedury, jako je „sp_server_info“ v hlavní databázi, která poskytuje informace o nainstalované verzi SQL Serveru:

EXEC sys.sp_server_info

Proč je postup nástroje Unit Testing odlišný

Jak již bylo zmíněno dříve, jednotkové testování obslužné procedury, která je volána uvnitř hlavní procedury, je mírně komplikované než jednotkové testování jednoduché uložené procedury.

Vzhledem k výše uvedenému příkladu zákaznického produktu musíme napsat test jednotky, abychom ověřili, že procedura obslužného programu funguje správně, a také je třeba napsat test jednotky, abychom ověřili, že hlavní procedura, která volá proceduru utility, také funguje správně, stejně jako schůzka obchodní požadavky.

To je znázorněno následovně:

Izolace od výzvy utility/hlavní procedury

Hlavním problémem při psaní testů jednotek pro proceduru, která zahrnuje proceduru utility, je ujistit se, že bychom se neměli starat o fungování procedury utility při psaní testu jednotky pro hlavní proceduru a totéž platí pro proceduru utility. . Toto je náročný úkol, který je třeba mít na paměti při psaní jednotkových testů pro takový scénář.
Oddělení od obslužného programu nebo hlavní procedury je nutností v závislosti na tom, která procedura je testována. V souvislosti s izolací při testování jednotky musíme mít na paměti následující věci:

  1. Oddělení od obslužné procedury při testování jednotky hlavní procedury.
  2. Oddělení od hlavní procedury při testování jednotky procedury utility.

Nezapomeňte, že tento článek je zaměřen na testování jednotky hlavního postupu tím, že jej izoluje od jeho obslužného postupu.

Vytvoření hlavní procedury a její pomocné procedury

Abychom mohli napsat test jednotky pro scénář, kde hlavní procedura používá obslužnou proceduru, musíme mít nejprve následující předpoklady:

  1. Ukázková databáze
  2. Obchodní požadavky

Nastavení ukázkové databáze (SQLBookShop)

Vytváříme jednoduchou dvoutabulkovou vzorovou databázi s názvem „SQLBookShop“, která obsahuje záznamy všech knih objednaných, jak je uvedeno níže:

Vytvořte ukázkovou databázi SQLBookShop následovně:

-- (1) Create SQLBookShop database
  CREATE DATABASE SQLBookShop;
  GO

Vytvořte a naplňte databázové objekty (tabulky) následovně:

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

Rychlá kontrola – vzorová databáze

Proveďte rychlou kontrolu databáze spuštěním zobrazení OrderedBooks pomocí následujícího kódu:

USE SQLBookShop

-- Run OrderedBooks view
SELECT
  ob.OrderID
 ,ob.OrderDate
 ,ob.Title AS BookTitle
 ,ob.Quantity
 ,ob.TotalPrice
FROM dbo.OrderedBooks ob

Vezměte prosím na vědomí, že používám dbForge Studio pro SQL Server, takže vzhled výstupu se může lišit, pokud stejný kód spustíte v SSMS (SQL Server Management Studio). Mezi skripty a jejich výsledky však není žádný rozdíl.

Obchodní požadavek na zobrazení nejnovější objednávky s dalšími informacemi

Vývojovému týmu byl zaslán obchodní požadavek, který uvádí, že „Koncový uživatel chce vědět o poslední objednávce konkrétní knihy spolu s informací, zda byla objednávka zadána ve všední den nebo o víkendu.“

Něco o TDDD

V tomto článku se striktně neřídíme testem řízeným vývojem databází (TDDD), ale důrazně doporučuji použít vývoj databází řízený testem (TDDD) k vytvoření jak hlavních, tak pomocných procedur, které začínají vytvořením testu jednotky pro kontrolu, zda existuje objekt, který nejprve selže, následuje vytvoření objektu a opětovné spuštění testu jednotky, který musí projít.
Podrobný návod naleznete v první části tohoto článku.

Identifikace postupu nástroje

Když vidíme obchodní požadavek, jedna věc je jistá, že potřebujeme obslužný postup, který nám řekne, zda je konkrétní datum všední den nebo víkend.

Vytvoření procedury nástroje (GetDayType)

Vytvořte obslužnou proceduru a nazvěte ji „GetDayType“ následovně:

-- 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

Rychlá kontrola – postup nástroje

Napište následující řádky kódu pro rychlou kontrolu postupu nástroje:

-- Quick check utility procedure
declare @DayType varchar(10)
EXEC uspGetDayType '20181001',@DayType output
select @DayType AS [Type of Day]

Vytvoření hlavní procedury (GetLatestOrderByBookId)

Vytvořte hlavní proceduru, abyste viděli poslední objednávku zadanou pro konkrétní knihu a také to, zda byla objednávka zadána ve všední den nebo víkend, a nazvěte ji „GetLatestOrderByBookId“, která obsahuje volání procedury nástroje takto:

-- 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

Rychlá kontrola – hlavní postup

Spusťte následující kód a zjistěte, zda postup funguje dobře nebo ne:

-- Get latest order for the bookid=6
EXEC uspGetLatestOrderByBookId @BookId = 6

Testování hlavní procedury volání procedury utility

Klíčem je zde pochopit rozdíl mezi jednotkovým testováním hlavního postupu a obslužného postupu.

V současné době se zaměřujeme na testování hlavní procedury, takže to znamená, že procedura obslužného programu musí být elegantně izolována od tohoto testu jednotky.

Použití špionážního postupu

Abychom se ujistili, že test hlavní procedury zůstane zaměřen na testování funkčnosti hlavní procedury, musíme použít špionážní proceduru poskytovanou tSQLt, která bude fungovat jako stub (placeholder) pro proceduru utility.

Podle tsqlt.org mějte prosím na paměti, že pokud špehujete proceduru, ve skutečnosti tuto proceduru netestujete, ale usnadňujete testování jednotky.

Například v našem případě, pokud chceme testovat hlavní proceduru jednotky, musíme zesměšňovat proceduru nástroje pomocí procedury spy, která nám usnadní testování hlavní procedury.

Vytvoření testu jednotky pro hlavní proceduru špionážní procedura

Vytvořte test databázové jednotky pro správnou kontrolu funkcí hlavní procedury.

Tento článek funguje pro dbForge Studio pro SQL Server (nebo pouze dbForge Unit Test) a SSMS (SQL Server Management Studio) . Upozorňujeme však, že při používání SSMS (SQL Server Management Studio) předpokládám, že jste již nainstalovali tSQLt Framework a jste připraveni psát testy jednotek.

Chcete-li vytvořit první test databázové jednotky, klikněte pravým tlačítkem na databázi SQLBookShop. V místní nabídce klikněte na Test jednotky a poté na Přidat nový test následovně:

Napište kód testu jednotky:

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

Spuštění testu jednotky pro hlavní postup

Spusťte test jednotky:

Gratulujeme, úspěšně jste jednotku otestovali uloženou proceduru tak, že jste ji po použití spy procedury izolovali od její obslužné procedury.

Další informace o testování jednotek naleznete v následujících částech mého předchozího článku o vývoji databází řízených testy (TDDD):

  • Jump to Start Test-Driven Database Development (TDDD) – Part 1
  • Jump to Start Test-Driven Database Development (TDDD) – Part 2
  • Jump to Start Test-Driven Database Development (TDDD) – Part 3

Co dělat

Nyní můžete vytvářet testy databázových jednotek pro mírně složité scénáře, kde uložené procedury volají pomocné procedury.

  1. Zkuste prosím změnit špionážní proceduru @CommandToExecute argument (hodnotu) na @CommandToExecute ='set @DayType =”Nothing” “ a uvidíte, že test nyní selže
  2. Zkuste prosím splnit obchodní požadavky v tomto článku pomocí testování databázového vývoje (TDDD)
  3. Zkuste prosím splnit další obchodní požadavek, abyste viděli nejnovější objednávku zadanou kterýmkoli zákazníkem využívajícím vývoj řízený testem (TDDD) se stejným obslužným postupem
  4. Zkuste vytvořit test jednotky pro obslužný postup izolováním hlavního postupu
  5. Zkuste si vytvořit jednotkový test pro proceduru, která volá dvě pomocné procedury

Užitečný nástroj:

dbForge Unit Test – intuitivní a pohodlné GUI pro implementaci automatizovaného testování jednotek v SQL Server Management Studio.


  1. Přidejte primární klíč s automatickým přírůstkem do existující tabulky v oracle

  2. Android SQLiteDB nedokončuje přidávání hodnot

  3. Statické funkce a pod

  4. Oracle DROP TABLE, POKUD EXISTUJE Alternativy