Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Đơn giản hóa quy trình kiểm tra đơn vị được lưu trữ chính còn gọi là thủ tục tiện ích

Bài viết này cung cấp hướng dẫn về cách kiểm tra đơn vị cơ sở dữ liệu một thủ tục được lưu trữ có chứa một thủ tục tiện ích bên trong nó.

Trong bài viết này, tôi sẽ thảo luận về một kịch bản kiểm thử đơn vị cơ sở dữ liệu khi một thủ tục được lưu trữ chính phụ thuộc vào một thủ tục tiện ích và thủ tục chính cần được kiểm thử đơn vị để đảm bảo rằng các yêu cầu được đáp ứng. Điều quan trọng là đảm bảo rằng một bài kiểm tra đơn vị chỉ có thể được viết cho một đơn vị mã, có nghĩa là chúng ta cần một bài kiểm tra đơn vị cho thủ tục chính và một bài kiểm tra đơn vị khác cho thủ tục tiện ích.

Kiểm tra đơn vị một thủ tục được lưu trữ đơn lẻ dễ dàng hơn so với kiểm tra đơn vị một thủ tục gọi một thủ tục tiện ích bên trong mã của nó.

Điều rất quan trọng là phải hiểu kịch bản thủ tục tiện ích và lý do tại sao nó khác với việc kiểm tra đơn vị một thủ tục được lưu trữ thông thường.

Tình huống:Thủ tục Tiện ích trong Quy trình Chính

Để hiểu kịch bản thủ tục tiện ích, chúng ta hãy bắt đầu bằng định nghĩa và ví dụ về thủ tục tiện ích:

Thủ tục Tiện ích là gì

Thủ tục tiện ích nói chung là một thủ tục nhỏ được (các) thủ tục chính sử dụng để thực hiện một số tác vụ cụ thể chẳng hạn như lấy một cái gì đó cho thủ tục chính hoặc thêm một cái gì đó vào thủ tục chính.

Một định nghĩa khác về thủ tục tiện ích là một thủ tục nhỏ được lưu trữ được viết cho mục đích bảo trì có thể liên quan đến các bảng hoặc khung nhìn hệ thống được gọi bằng bất kỳ số lượng thủ tục nào hoặc thậm chí trực tiếp.

Ví dụ về Thủ tục Tiện ích

Hãy nghĩ về tình huống khách hàng đặt hàng sản phẩm trong đó khách hàng đặt hàng cho một sản phẩm cụ thể. Nếu chúng tôi tạo quy trình chính để giúp chúng tôi nhận được tất cả các đơn hàng được đặt bởi một khách hàng cụ thể thì một thủ tục tiện ích có thể được sử dụng để giúp chúng tôi hiểu liệu từng đơn hàng đã được khách hàng đặt vào ngày trong tuần hay cuối tuần.
Bằng cách này, a Quy trình tiện ích nhỏ có thể được viết để trả lại "Ngày trong tuần" hoặc "Ngày cuối tuần" dựa trên ngày sản phẩm được khách hàng đặt hàng.

Một ví dụ khác có thể là các thủ tục được hệ thống lưu trữ chẳng hạn như “sp_server_info” trong cơ sở dữ liệu chính cung cấp thông tin về phiên bản đã cài đặt của SQL Server:

EXEC sys.sp_server_info

Tại sao Quy trình Tiện ích Kiểm tra Đơn vị lại Khác nhau

Như đã thảo luận trước đó, kiểm thử đơn vị một thủ tục tiện ích được gọi bên trong thủ tục chính hơi phức tạp hơn kiểm thử đơn vị một thủ tục lưu trữ đơn giản.

Xét ví dụ về đơn đặt hàng-sản phẩm của khách hàng được đề cập ở trên, chúng ta cần viết một bài kiểm tra đơn vị để kiểm tra thủ tục tiện ích có hoạt động tốt hay không và cũng phải viết một bài kiểm tra đơn vị để kiểm tra thủ tục chính mà gọi thủ tục tiện ích cũng hoạt động bình thường cũng như đáp ứng. (các) yêu cầu kinh doanh.

Điều này được minh họa như sau:

Tách biệt khỏi Tiện ích / Thử thách thủ tục chính

Thách thức chính khi viết (các) kiểm thử đơn vị cho thủ tục liên quan đến thủ tục tiện ích là đảm bảo rằng chúng ta không phải lo lắng về hoạt động của thủ tục tiện ích khi viết kiểm thử đơn vị cho thủ tục chính và điều này cũng đúng với thủ tục tiện ích . Đây là một nhiệm vụ khó khăn cần được ghi nhớ khi viết các bài kiểm tra đơn vị cho một tình huống như vậy.
Việc tách biệt khỏi tiện ích hoặc thủ tục chính là điều bắt buộc, tùy thuộc vào thủ tục nào đang được thử nghiệm. Chúng tôi phải ghi nhớ những điều sau trong bối cảnh cô lập trong khi thử nghiệm đơn vị:

  1. Tách biệt khỏi thủ tục tiện ích khi đơn vị thử nghiệm thủ tục chính.
  2. Tách biệt khỏi thủ tục chính khi thủ tục tiện ích thử nghiệm đơn vị.

Hãy nhớ bài viết này tập trung vào việc kiểm tra đơn vị thủ tục chính bằng cách tách nó khỏi quy trình tiện ích của nó.

Tạo Thủ tục Chính và Thủ tục Tiện ích của nó

Để viết một bài kiểm tra đơn vị cho một tình huống trong đó thủ tục tiện ích được sử dụng bởi thủ tục chính, trước tiên chúng ta cần có các điều kiện tiên quyết sau:

  1. Cơ sở dữ liệu Mẫu
  2. (Các) Yêu cầu Kinh doanh

Thiết lập cơ sở dữ liệu mẫu (SQLBookShop)

Chúng tôi đang tạo một cơ sở dữ liệu mẫu gồm hai bảng đơn giản có tên “SQLBookShop” chứa các bản ghi của tất cả các sách được đặt hàng như hình dưới đây:

Tạo cơ sở dữ liệu mẫu SQLBookShop như sau:

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

Tạo và điền các đối tượng cơ sở dữ liệu (bảng) như sau:

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

Kiểm tra nhanh - Cơ sở dữ liệu mẫu

Thực hiện kiểm tra nhanh cơ sở dữ liệu bằng cách chạy chế độ xem Sách có thứ tự sử dụng mã sau:

USE SQLBookShop

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

Xin lưu ý rằng tôi đang sử dụng dbForge Studio cho SQL Server nên giao diện đầu ra có thể khác nếu bạn chạy cùng một mã trong SSMS (SQL Server Management Studio). Tuy nhiên, không có sự khác biệt giữa các tập lệnh và kết quả của chúng.

Yêu cầu kinh doanh để xem đơn đặt hàng mới nhất với thông tin bổ sung

Một yêu cầu kinh doanh đã được gửi đến nhóm nhà phát triển, trong đó nói rằng “Người dùng cuối muốn biết về đơn đặt hàng gần đây nhất được đặt cho một cuốn sách cụ thể cùng với thông tin liệu đơn đặt hàng được đặt vào ngày trong tuần hay cuối tuần”

Đôi nét về TDDD

Chúng tôi không tuân thủ nghiêm ngặt phát triển cơ sở dữ liệu hướng thử nghiệm (TDDD) trong bài viết này nhưng tôi thực sự khuyên bạn nên sử dụng phát triển cơ sở dữ liệu hướng thử nghiệm (TDDD) để tạo cả thủ tục chính và thủ tục tiện ích, bắt đầu bằng cách tạo thử nghiệm đơn vị để kiểm tra xem đối tượng có tồn tại hay không không thành công lúc đầu, tiếp theo là tạo đối tượng và chạy lại bài kiểm tra đơn vị phải vượt qua.
Để xem hướng dẫn chi tiết, vui lòng tham khảo phần đầu tiên của bài viết này.

Quy trình Xác định Tiện ích

Nhìn thấy yêu cầu kinh doanh, chắc chắn một điều là chúng ta cần một thủ tục tiện ích có thể cho chúng ta biết một ngày cụ thể là ngày trong tuần hay cuối tuần.

Tạo thủ tục tiện ích (GetDayType)

Tạo một thủ tục tiện ích và gọi nó là “GetDayType” như sau:

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

Kiểm tra nhanh - Thủ tục Tiện ích

Viết các dòng mã sau để nhanh chóng kiểm tra thủ tục tiện ích:

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

Tạo thủ tục chính (GetLatestOrderByBookId)

Tạo quy trình chính để xem đơn đặt hàng gần đây nhất được đặt cho một cuốn sách cụ thể và cả đơn đặt hàng được đặt vào ngày trong tuần hay cuối tuần và gọi nó là “GetLatestOrderByBookId” chứa lệnh gọi cho thủ tục tiện ích như sau:

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

Kiểm tra nhanh - Quy trình chính

Chạy mã sau để xem liệu quy trình có hoạt động tốt hay không:

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

Quy trình chính Kiểm tra đơn vị Quy trình gọi tiện ích

Chìa khóa ở đây là hiểu sự khác biệt giữa quy trình chính và thủ tục kiểm tra đơn vị.

Chúng tôi hiện đang tập trung vào kiểm tra đơn vị thủ tục chính, vì vậy, điều này có nghĩa là quy trình tiện ích cần được tách biệt một cách khéo léo với kiểm thử đơn vị này.

Sử dụng Thủ tục Gián điệp

Để đảm bảo rằng kiểm tra đơn vị thủ tục chính vẫn tập trung vào kiểm tra chức năng của thủ tục chính, chúng tôi phải sử dụng thủ tục gián điệp do tSQLt cung cấp, thủ tục này sẽ hoạt động như một sơ khai (trình giữ chỗ) cho thủ tục tiện ích.

Theo tsqlt.org, hãy nhớ rằng nếu bạn đang theo dõi một thủ tục, bạn không thực sự kiểm tra đơn vị thủ tục đó thay vì bạn đang làm cho thủ tục khác liên quan đến quy trình mà bạn đang gián điệp được kiểm tra đơn vị dễ dàng hơn.

Ví dụ:trong trường hợp của chúng ta, nếu chúng ta muốn kiểm tra đơn vị thủ tục chính thì chúng ta phải mô phỏng thủ tục tiện ích bằng cách sử dụng thủ tục gián điệp, điều này sẽ giúp chúng ta kiểm tra đơn vị thủ tục chính dễ dàng hơn.

Tạo đơn vị kiểm tra cho quy trình chính Thủ tục gián điệp tiện ích

Tạo một bài kiểm tra đơn vị cơ sở dữ liệu để kiểm tra các chức năng của thủ tục chính một cách chính xác.

Bài viết này phù hợp với dbForge Studio dành cho SQL Server (hoặc chỉ Kiểm tra đơn vị dbForge) SSMS (SQL Server Management Studio) . Tuy nhiên, xin lưu ý rằng khi sử dụng SSMS (SQL Server Management Studio), tôi giả sử bạn đã cài đặt tSQLt Framework và sẵn sàng viết các bài kiểm tra đơn vị.

Để tạo bài kiểm tra đơn vị cơ sở dữ liệu đầu tiên, bấm chuột phải vào cơ sở dữ liệu SQLBookShop. Trên menu lối tắt, bấm Kiểm tra Đơn vị và sau đó Thêm Kiểm tra Mới như sau:

Viết mã kiểm tra đơn vị:

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

Kiểm tra Đơn vị Chạy cho Quy trình Chính

Chạy thử nghiệm đơn vị:

Xin chúc mừng, bạn đã kiểm tra đơn vị thành công một quy trình được lưu trữ bằng cách cô lập nó khỏi quy trình tiện ích của nó sau khi sử dụng quy trình gián điệp.

Để biết thêm thông tin về kiểm thử đơn vị, vui lòng xem qua các phần sau của bài viết trước của tôi về phát triển cơ sở dữ liệu hướng kiểm tra (TDDD):

  • Bước tới Bắt đầu Phát triển Cơ sở dữ liệu Theo hướng Thử nghiệm (TDDD) - Phần 1
  • Bước tới Bắt đầu Phát triển Cơ sở dữ liệu Theo hướng Thử nghiệm (TDDD) - Phần 2
  • Bước tới Bắt đầu Phát triển Cơ sở dữ liệu Theo hướng Thử nghiệm (TDDD) - Phần 3

Việc cần làm

Giờ đây, bạn có thể tạo các bài kiểm tra đơn vị cơ sở dữ liệu cho các tình huống hơi phức tạp trong đó các thủ tục được lưu trữ gọi các thủ tục tiện ích.

  1. Vui lòng thử thay đổi quy trình gián điệp @CommandToExecute đối số (giá trị) thành @CommandToExecute =‘set @DayType =” Nothing ”‘ và kiểm tra sẽ thất bại ngay bây giờ
  2. Vui lòng thử đáp ứng yêu cầu kinh doanh trong bài viết này bằng cách sử dụng phát triển cơ sở dữ liệu theo hướng thử nghiệm (TDDD)
  3. Vui lòng thử đáp ứng một yêu cầu kinh doanh khác để xem đơn đặt hàng gần đây nhất được đặt bởi bất kỳ khách hàng nào bằng cách sử dụng phát triển theo hướng thử nghiệm (TDDD) liên quan đến cùng một quy trình tiện ích
  4. Vui lòng thử tạo một bài kiểm tra đơn vị cho quy trình tiện ích bằng cách tách riêng quy trình chính
  5. Hãy thử tự tạo một bài kiểm tra đơn vị cho một thủ tục gọi hai thủ tục tiện ích

Công cụ hữu ích:

dbForge Unit Test - một GUI trực quan và thuận tiện để triển khai kiểm thử đơn vị tự động trong SQL Server Management Studio.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hướng dẫn tham gia SQL

  2. SQL, thêm dữ liệu vào bảng

  3. Mức độ tương thích và lớp lót ước tính số lượng

  4. Lược đồ bông tuyết

  5. Xử lý cơ sở dữ liệu SQL với PyQt:Khái niệm cơ bản