연습: SQL Server 단위 테스트 만들기 및 실행
이 연습에서는 여러 저장 프로시저의 동작을 확인하는 SQL Server 단위 테스트를 만듭니다. SQL Server 단위 테스트를 만들면 잘못된 애플리케이션 동작을 유발할 수 있는 코드 결함을 확인하는 데 도움이 됩니다. SQL Server 단위 테스트와 애플리케이션 테스트는 자동화된 테스트 집합의 일부로 실행할 수 있습니다.
이 연습에서는 다음 작업을 수행합니다.
단위 테스트 중 하나가 저장 프로시저에서 오류를 감지한 후에는 해당 오류를 수정하고 테스트를 다시 실행합니다.
필수 조건
이 연습을 완료하려면 데이터베이스를 만들고 배포할 수 있는 권한이 있는 데이터베이스 서버(또는 LocalDB 데이터베이스)에 연결할 수 있어야 합니다. 자세한 내용은 Visual Studio의 데이터베이스 기능에 필요한 권한을 참조하세요.
데이터베이스 스키마가 포함된 스크립트 만들기
스키마를 가져올 수 있는 스크립트를 만들려면
파일 메뉴에서 새로 만들기를 가리킨 다음 파일을 클릭합니다.
새 파일 대화 상자가 표시됩니다.
범주 목록에서 아직 강조 표시되지 않은 경우 일반을 클릭합니다.
템플릿 창에서 Sql 파일을 클릭한 다음 열기를 클릭합니다.
Transact-SQL 편집기가 열립니다.
다음 Transact-SQL 코드를 복사해서 Transact-SQL 편집기에 붙여넣습니다.
PRINT N'Creating Sales...'; GO CREATE SCHEMA [Sales] AUTHORIZATION [dbo]; GO PRINT N'Creating Sales.Customer...'; GO CREATE TABLE [Sales].[Customer] ( [CustomerID] INT IDENTITY (1, 1) NOT NULL, [CustomerName] NVARCHAR (40) NOT NULL, [YTDOrders] INT NOT NULL, [YTDSales] INT NOT NULL ); GO PRINT N'Creating Sales.Orders...'; GO CREATE TABLE [Sales].[Orders] ( [CustomerID] INT NOT NULL, [OrderID] INT IDENTITY (1, 1) NOT NULL, [OrderDate] DATETIME NOT NULL, [FilledDate] DATETIME NULL, [Status] CHAR (1) NOT NULL, [Amount] INT NOT NULL ); GO PRINT N'Creating Sales.Def_Customer_YTDOrders...'; GO ALTER TABLE [Sales].[Customer] ADD CONSTRAINT [Def_Customer_YTDOrders] DEFAULT 0 FOR [YTDOrders]; GO PRINT N'Creating Sales.Def_Customer_YTDSales...'; GO ALTER TABLE [Sales].[Customer] ADD CONSTRAINT [Def_Customer_YTDSales] DEFAULT 0 FOR [YTDSales]; GO PRINT N'Creating Sales.Def_Orders_OrderDate...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [Def_Orders_OrderDate] DEFAULT GetDate() FOR [OrderDate]; GO PRINT N'Creating Sales.Def_Orders_Status...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [Def_Orders_Status] DEFAULT 'O' FOR [Status]; GO PRINT N'Creating Sales.PK_Customer_CustID...'; GO ALTER TABLE [Sales].[Customer] ADD CONSTRAINT [PK_Customer_CustID] PRIMARY KEY CLUSTERED ([CustomerID] ASC) WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF); GO PRINT N'Creating Sales.PK_Orders_OrderID...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [PK_Orders_OrderID] PRIMARY KEY CLUSTERED ([OrderID] ASC) WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF); GO PRINT N'Creating Sales.FK_Orders_Customer_CustID...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [FK_Orders_Customer_CustID] FOREIGN KEY ([CustomerID]) REFERENCES [Sales].[Customer] ([CustomerID]) ON DELETE NO ACTION ON UPDATE NO ACTION; GO PRINT N'Creating Sales.CK_Orders_FilledDate...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [CK_Orders_FilledDate] CHECK ((FilledDate >= OrderDate) AND (FilledDate < '01/01/2030')); GO PRINT N'Creating Sales.CK_Orders_OrderDate...'; GO ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [CK_Orders_OrderDate] CHECK ((OrderDate > '01/01/2005') and (OrderDate < '01/01/2030')); GO PRINT N'Creating Sales.uspCancelOrder...'; GO CREATE PROCEDURE [Sales].[uspCancelOrder] @OrderID INT AS BEGIN DECLARE @Delta INT, @CustomerID INT BEGIN TRANSACTION SELECT @Delta = [Amount], @CustomerID = [CustomerID] FROM [Sales].[Orders] WHERE [OrderID] = @OrderID; UPDATE [Sales].[Orders] SET [Status] = 'X' WHERE [OrderID] = @OrderID; UPDATE [Sales].[Customer] SET YTDOrders = YTDOrders - @Delta WHERE [CustomerID] = @CustomerID COMMIT TRANSACTION END GO PRINT N'Creating Sales.uspFillOrder...'; GO CREATE PROCEDURE [Sales].[uspFillOrder] @OrderID INT, @FilledDate DATETIME AS BEGIN DECLARE @Delta INT, @CustomerID INT BEGIN TRANSACTION SELECT @Delta = [Amount], @CustomerID = [CustomerID] FROM [Sales].[Orders] WHERE [OrderID] = @OrderID; UPDATE [Sales].[Orders] SET [Status] = 'F', [FilledDate] = @FilledDate WHERE [OrderID] = @OrderID; UPDATE [Sales].[Customer] SET YTDSales = YTDSales - @Delta WHERE [CustomerID] = @CustomerID COMMIT TRANSACTION END GO PRINT N'Creating Sales.uspNewCustomer...'; GO CREATE PROCEDURE [Sales].[uspNewCustomer] @CustomerName NVARCHAR (40) AS BEGIN INSERT INTO [Sales].[Customer] (CustomerName) VALUES (@CustomerName); RETURN SCOPE_IDENTITY() END GO PRINT N'Creating Sales.uspPlaceNewOrder...'; GO CREATE PROCEDURE [Sales].[uspPlaceNewOrder] @CustomerID INT, @Amount INT, @OrderDate DATETIME, @Status CHAR (1)='O' AS BEGIN DECLARE @RC INT BEGIN TRANSACTION INSERT INTO [Sales].[Orders] (CustomerID, OrderDate, FilledDate, Status, Amount) VALUES (@CustomerID, @OrderDate, NULL, @Status, @Amount) SELECT @RC = SCOPE_IDENTITY(); UPDATE [Sales].[Customer] SET YTDOrders = YTDOrders + @Amount WHERE [CustomerID] = @CustomerID COMMIT TRANSACTION RETURN @RC END GO CREATE PROCEDURE [Sales].[uspShowOrderDetails] @CustomerID INT=0 AS BEGIN SELECT [C].[CustomerName], CONVERT(date, [O].[OrderDate]), CONVERT(date, [O].[FilledDate]), [O].[Status], [O].[Amount] FROM [Sales].[Customer] AS C INNER JOIN [Sales].[Orders] AS O ON [O].[CustomerID] = [C].[CustomerID] WHERE [C].[CustomerID] = @CustomerID END GO
파일을 저장합니다. 다음 절차에서 이 스크립트를 사용해야 하므로 위치를 기록해 둡니다.
파일 메뉴에서 솔루션 닫기를 클릭합니다.
그런 다음 데이터베이스 프로젝트를 만들고 앞에서 만든 스크립트에서 스키마를 가져옵니다.
데이터베이스 프로젝트를 만들고 스키마를 가져옵니다.
데이터베이스 프로젝트를 만들려면
파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.
새 프로젝트 대화 상자가 나타납니다.
설치된 템플릿에서 SQL Server 노드를 선택한 후 SQL Server 데이터베이스 프로젝트를 선택합니다.
이름에 SimpleUnitTestDB를 입력합니다.
선택되어 있지 않다면 솔루션용 디렉터리 만들기 확인란을 선택합니다.
소스 제어에 추가 확인란의 선택이 아직 취소되지 않은 경우 취소하고 확인을 클릭합니다.
데이터베이스 프로젝트가 만들어지고 솔루션 탐색기에 나타납니다. 다음으로 스크립트에서 데이터베이스 스키마를 가져옵니다.
스크립트에서 데이터베이스 스키마를 가져오려면
프로젝트 메뉴에서 가져오기를 클릭한 후 스크립트(*.sql)를 클릭합니다.
시작 페이지를 읽은 후 다음 을 클릭합니다.
찾아보기를 클릭하고 .sql 파일을 저장한 디렉터리로 이동합니다.
.sql 파일을 두 번 클릭하고 마침을 클릭합니다.
스크립트를 가져오고 해당 스크립트에 정의된 개체가 데이터베이스 프로젝트에 추가됩니다.
요약을 검토한 다음 마침을 클릭하여 작업을 완료합니다.
참고 항목
Sales.uspFillOrder 프로시저에는 이 절차의 뒷부분에서 검색하고 수정할 의도적인 코딩 오류가 포함되어 있습니다.
결과 프로젝트를 검사하려면
솔루션 탐색기에서 프로젝트로 가져온 스크립트 파일을 검사합니다.
SQL Server 개체 탐색기의 프로젝트 노드에서 데이터베이스를 확인합니다.
LocalDB에 배포
기본적으로 F5 키를 누르면 데이터베이스를 LocalDB 데이터베이스에 배포(또는 게시)합니다. 프로젝트 속성 페이지의 디버그 탭으로 이동하고 연결 문자열을 변경하여 데이터베이스 위치를 변경할 수 있습니다.
SQL Server 단위 테스트 만들기
저장 프로시저에 대한 SQL Server 단위 테스트를 만들려면
SQL Server 개체 탐색기에서 SimpleUnitTestDB의 프로젝트 노드를 확장하고 프로그래밍 기능 및 저장 프로시저 노드를 차례로 확장합니다.
저장 프로시저 중 하나를 마우스 오른쪽 단추로 클릭하고 단위 테스트 만들기를 클릭하여 단위 테스트 만들기 대화 상자를 표시합니다.
Sales.uspCancelOrder, Sales.uspFillOrder, Sales.uspNewCustomer, Sales.uspPlaceNewOrder, 및 Sales.uspShowOrderDetails의 다섯 개 저장 프로시저 모두에 대한 확인란을 선택합니다.
프로젝트 드롭다운 목록에서 새 Visual C# 테스트 프로젝트 만들기를 선택합니다.
프로젝트 이름 및 클래스 이름에 대한 기본 이름을 적용하고 확인을 클릭합니다.
테스트 구성 대화 상자의 다음 데이터 연결을 사용하여 단위 테스트 실행에서 이 연습의 앞부분에서 배포한 데이터베이스에 대한 연결을 지정합니다. 예를 들어 LocalDB인 기본 배포 위치를 사용한 경우 새 연결 지정 (LocalDB)\Projects를 클릭합니다. 그런 다음 데이터베이스의 이름을 선택합니다. 그리고 확인을 클릭하여 연결 속성 대화 상자를 닫습니다.
참고 항목
제한된 권한을 포함하는 뷰 또는 저장 프로시저를 테스트해야 할 경우 일반적으로 이 단계에서 해당 연결을 지정합니다. 그런 다음, 더 광범위한 권한으로 보조 연결을 지정하여 테스트의 유효성을 검사합니다. 보조 연결이 있는 경우 해당 사용자를 데이터베이스 프로젝트에 추가하고 배포 전 스크립트에서 해당 사용자에 대한 로그인을 만들어야 합니다.
테스트 구성 대화 상자의 배포 섹션에서 단위 테스트를 실행하기 전에 데이터베이스 프로젝트를 자동으로 배포 확인란을 선택합니다.
데이터베이스 프로젝트에서 SimpleUnitTestDB.sqlproj를 클릭합니다.
배포 구성에서 디버그를 클릭합니다.
SQL Server 단위 테스트의 일부로 테스트 데이터를 생성할 수도 있습니다. 이 연습에서는 테스트가 자체 데이터를 만들기 때문에 해당 단계를 건너뜁니다.
확인을 클릭합니다.
테스트 프로젝트가 빌드되고 SQL Server 단위 테스트 디자이너가 나타납니다. 그런 다음, SQL Server 단위 테스트의 Transact-SQL 스크립트에서 테스트 논리를 업데이트합니다.
테스트 논리 정의
이 매우 간단한 데이터베이스에는 Customer와 Order라는 두 개의 테이블이 있습니다. 다음 저장 프로시저를 사용하여 데이터베이스를 업데이트합니다.
uspNewCustomer - 이 저장 프로시저는 Customer 테이블에 고객의 YTDOrders 및 YTDSales 열을 0으로 설정하는 레코드를 추가합니다.
uspPlaceNewOrder - 이 저장 프로시저는 지정된 고객에 대한 레코드를 Orders 테이블에 추가하고 Customer 테이블에 있는 해당 레코드에서 YTDOrders 값을 업데이트합니다.
uspFillOrder - 이 저장 프로시저는 상태를 'O'에서 'F'로 변경하여 Orders 테이블에서 레코드를 업데이트하고 Customer 테이블의 해당 레코드에서 YTDSales 값을 증분합니다.
uspCancelOrder - 이 저장 프로시저는 상태를 'O'에서 'X'로 변경하여 Orders 테이블에서 레코드를 업데이트하고 Customer 테이블의 해당 레코드에서 YTDOrders 값을 감소합니다.
uspShowOrderDetails - 이 저장 프로시저는 Orders 테이블을 사용자 지정 테이블과 조인하고 특정 고객에 대한 레코드를 표시합니다.
참고 항목
이 예제에서는 간단한 SQL Server 단위 테스트를 만드는 방법을 보여 줍니다. 실제 환경의 데이터베이스에서는 특정 고객에 대해 상태가 'O' 또는 'F'인 모든 주문의 합계를 계산할 수 있습니다. 이 연습의 프로시저에는 오류 처리가 포함되지 않습니다. 예를 들어 이미 채워진 주문에 대해 uspFillOrder를 호출할 수 없습니다.
테스트에서는 데이터베이스가 클린 상태에서 시작된다고 가정합니다. 다음 조건을 확인하는 테스트를 만듭니다.
uspNewCustomer - 저장 프로시저를 실행한 후 고객 테이블에 하나의 행이 포함되어 있는지 확인합니다.
uspPlaceNewOrder - CustomerID가 1인 고객의 경우 $100에 주문합니다. 해당 고객의 YTDOrders 금액이 100이고 YTDSales 금액이 0인지 확인합니다.
uspFillOrder - CustomerID가 1인 고객의 경우 $50에 주문을 합니다. 해당 순서를 채웁니다. YTDOrders 및 YTDSales 값이 모두 50인지 확인합니다.
uspShowOrderDetails - CustomerID가 1인 고객의 경우 $100, $50 및 $5에 주문을 합니다. uspShowOrderDetails가 올바른 수의 열을 반환하고 결과 집합에 예상된 체크섬이 있는지 확인합니다.
참고 항목
전체 SQL Server 단위 테스트 집합의 경우 일반적으로 다른 열이 올바르게 설정되었는지를 확인합니다. 이 연습을 관리 가능한 크기로 유지하기 위해 uspCancelOrder의 동작을 확인하는 방법은 설명하지 않습니다.
uspNewCustomer에 대한 SQL Server 단위 테스트를 작성하려면
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspNewCustomerTest를 클릭하고 인접한 목록에서 테스트가 강조 표시되어 있는지 확인합니다.
이전 단계를 수행한 후 단위 테스트에서 테스트 작업에 대한 테스트 스크립트를 만들 수 있습니다.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
-- ssNoVersion unit test for Sales.uspNewCustomer DECLARE @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @CustomerName = 'Fictitious Customer'; EXECUTE @RC = [Sales].[uspNewCustomer] @CustomerName; SELECT * FROM [Sales].[Customer];
테스트 조건 창에서 결과 불충분 테스트 조건을 클릭하고 테스트 조건 삭제 아이콘(빨간색 X)을 클릭합니다.
테스트 조건 창에서 목록에서 행 개수를 클릭한 다음 테스트 조건 추가 아이콘(녹색 +)을 클릭합니다.
속성 창을 열고(테스트 조건을 선택하고 F4 키를 누릅니다) 행 개수 속성을 1로 설정합니다.
파일 메뉴에서 모두 저장을 클릭합니다.
이제 uspPlaceNewOrder에 대해 단위 테스트 논리를 정의합니다.
uspPlaceNewOrder에 대한 SQL Server 단위 테스트를 작성하려면
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspPlaceNewOrderTest를 클릭하고 인접한 목록에서 테스트가 강조 표시되어 있는지 확인합니다.
이 단계를 수행한 후 단위 테스트에서 테스트 작업에 대한 테스트 스크립트를 만들 수 있습니다.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
-- ssNoVersion unit test for Sales.uspPlaceNewOrder DECLARE @RC AS INT, @CustomerID AS INT, @Amount AS INT, @OrderDate AS DATETIME, @Status AS CHAR (1); DECLARE @CustomerName AS NVARCHAR(40); SELECT @RC = 0, @CustomerID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @OrderDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- place an order for that customer EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, @Amount, @OrderDate, @Status; -- verify that the YTDOrders value is correct. SELECT @RC = [YTDOrders] FROM [Sales].[Customer] WHERE [CustomerID] = @CustomerID SELECT @RC AS RC
테스트 조건 창에서 결과 불충분 테스트 조건을 클릭하고 테스트 조건 삭제를 클릭합니다.
테스트 조건 창에서 목록에서 스칼라 값을 클릭한 다음 테스트 조건 추가를 클릭합니다.
속성 창에서 예상된 값 속성을 100으로 설정합니다.
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspPlaceNewOrderTest를 클릭하고 인접한 목록에서 테스트 이전이 강조 표시되어 있는지 확인합니다.
이 단계를 수행한 후 테스트를 실행하는 데 필요한 상태로 데이터를 배치하는 문을 지정할 수 있습니다. 이 예제에서는 주문을 하기 전에 고객 레코드를 만들어야 합니다.
테스트 전 스크립트를 만들려면 여기를 클릭하여 만들기를 클릭하세요.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
/* Add Transact-SQL statements here that you want to run before the test script is run. */ -- Add a customer for this test with the name 'Fictitious Customer' DECLARE @NewCustomerID AS INT, @CustomerID AS INT, @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @NewCustomerID = 0, @CustomerID = 0, @CustomerName = N'Fictitious Customer'; IF NOT EXISTS(SELECT * FROM [Sales].[Customer] WHERE CustomerName = @CustomerName) BEGIN EXECUTE @NewCustomerID = [Sales].[uspNewCustomer] @CustomerName; END -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- delete any old records in the Orders table and clear out the YTD Sales/Orders fields DELETE from [Sales].[Orders] WHERE [CustomerID] = @CustomerID; UPDATE [Sales].[Customer] SET YTDOrders = 0, YTDSales = 0 WHERE [CustomerID] = @CustomerID;
파일 메뉴에서 모두 저장을 클릭합니다.
이제 uspFillOrder에 대해 단위 테스트를 만듭니다.
uspFillOrder에 대한 SQL Server 단위 테스트를 작성하려면
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspFillOrderTest를 클릭하고 인접한 목록에서 테스트가 강조 표시되어 있는지 확인합니다.
이 단계를 수행한 후 단위 테스트에서 테스트 작업에 대한 테스트 스크립트를 만들 수 있습니다.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
-- ssNoVersion unit test for Sales.uspFillOrder DECLARE @RC AS INT, @CustomerID AS INT, @Amount AS INT, @FilledDate AS DATETIME, @Status AS CHAR (1); DECLARE @CustomerName AS NVARCHAR(40), @OrderID AS INT; SELECT @RC = 0, @CustomerID = 0, @OrderID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @FilledDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- Get the most recently added order. SELECT @OrderID = MAX([OrderID]) FROM [Sales].[Orders] WHERE [CustomerID] = @CustomerID; -- fill an order for that customer EXECUTE @RC = [Sales].[uspFillOrder] @OrderID, @FilledDate; -- verify that the YTDOrders value is correct. SELECT @RC = [YTDSales] FROM [Sales].[Customer] WHERE [CustomerID] = @CustomerID SELECT @RC AS RC;
테스트 조건 창에서 결과 불충분 테스트 조건을 클릭하고 테스트 조건 삭제를 클릭합니다.
테스트 조건 창에서 목록에서 스칼라 값을 클릭한 다음 테스트 조건 추가를 클릭합니다.
속성 창에서 예상된 값 속성을 100으로 설정합니다.
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspFillOrderTest를 클릭하고 인접한 목록에서 테스트 이전이 강조 표시되어 있는지 확인합니다. 이 단계를 수행한 후 테스트를 실행하는 데 필요한 상태로 데이터를 배치하는 문을 지정할 수 있습니다. 이 예제에서는 주문을 하기 전에 고객 레코드를 만들어야 합니다.
테스트 전 스크립트를 만들려면 여기를 클릭하여 만들기를 클릭하세요.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
/* Add Transact-SQL statements here that you want to run before the test script is run. */ BEGIN TRANSACTION -- Add a customer for this test with the name 'CustomerB' DECLARE @NewCustomerID AS INT, @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @NewCustomerID = 0, @CustomerName = N'Fictitious Customer'; IF NOT EXISTS(SELECT * FROM [Sales].[Customer] WHERE CustomerName = @CustomerName) BEGIN EXECUTE @NewCustomerID = [Sales].[uspNewCustomer] @CustomerName; END DECLARE @CustomerID AS INT, @Amount AS INT, @OrderDate AS DATETIME, @Status AS CHAR (1); SELECT @RC = 0, @CustomerID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @OrderDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- delete any old records in the Orders table and clear out the YTD Sales/Orders fields DELETE from [Sales].[Orders] WHERE [CustomerID] = @CustomerID; UPDATE [Sales].[Customer] SET YTDOrders = 0, YTDSales = 0 WHERE [CustomerID] = @CustomerID; -- place an order for that customer EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, @Amount, @OrderDate, @Status; COMMIT TRANSACTION
파일 메뉴에서 모두 저장을 클릭합니다.
uspShowOrderDetails에 대한 SQL Server 단위 테스트를 작성하려면
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspShowOrderDetailsTest를 클릭하고 인접한 목록에서 테스트가 강조 표시되어 있는지 확인합니다.
이 단계를 수행한 후 단위 테스트에서 테스트 작업에 대한 테스트 스크립트를 만들 수 있습니다.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
-- ssNoVersion unit test for Sales.uspFillOrder DECLARE @RC AS INT, @CustomerID AS INT, @Amount AS INT, @FilledDate AS DATETIME, @Status AS CHAR (1); DECLARE @CustomerName AS NVARCHAR(40), @OrderID AS INT; SELECT @RC = 0, @CustomerID = 0, @OrderID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @FilledDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- fill an order for that customer EXECUTE @RC = [Sales].[uspShowOrderDetails] @CustomerID; SELECT @RC AS RC;
테스트 조건 창에서 결과 불충분 테스트 조건을 클릭하고 테스트 조건 삭제를 클릭합니다.
테스트 조건 창의 목록에서 예상된 스키마를 클릭한 다음 테스트 조건 추가를 클릭합니다.
속성 창의 구성 속성에서 찾아보기 단추를 클릭합니다('...').
expectedSchemaCondition1에 대한 구성 대화 상자에서 데이터베이스에 대한 연결을 지정합니다. 예를 들어 LocalDB인 기본 배포 위치를 사용한 경우 새 연결 지정 (LocalDB)\Projects를 클릭합니다. 그런 다음 데이터베이스의 이름을 선택합니다.
검색을 클릭합니다. 필요한 경우 데이터가 표시될 때까지 검색을 클릭합니다.
단위 테스트의 Transact-SQL 본문이 실행되고 결과 스키마가 대화 상자에 표시됩니다. 테스트 전 코드가 실행되지 않았으므로 데이터가 반환되지 않습니다. 데이터가 아닌 스키마만 확인하므로 괜찮습니다.
확인을 클릭합니다.
예상된 스키마는 테스트 조건과 함께 저장됩니다.
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspShowOrderDetailsTest를 클릭하고 인접한 목록에서 테스트 이전이 강조 표시되어 있는지 확인합니다. 이 단계를 수행한 후 테스트를 실행하는 데 필요한 상태로 데이터를 배치하는 문을 지정할 수 있습니다. 이 예제에서는 주문을 하기 전에 고객 레코드를 만들어야 합니다.
테스트 전 스크립트를 만들려면 여기를 클릭하여 만들기를 클릭하세요.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
/* Add Transact-SQL statements here to run before the test script is run. */ BEGIN TRANSACTION -- Add a customer for this test with the name 'FictitiousCustomer' DECLARE @NewCustomerID AS INT, @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @NewCustomerID = 0, @CustomerName = N'Fictitious Customer'; IF NOT EXISTS(SELECT * FROM [Sales].[Customer] WHERE CustomerName = @CustomerName) BEGIN EXECUTE @NewCustomerID = [Sales].[uspNewCustomer] @CustomerName; END DECLARE @CustomerID AS INT, @Amount AS INT, @OrderDate AS DATETIME, @Status AS CHAR (1); SELECT @RC = 0, @CustomerID = 0, @CustomerName = N'Fictitious Customer', @OrderDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- delete any old records in the Orders table and clear out the YTD Sales/Orders fields DELETE from [Sales].[Orders] WHERE [CustomerID] = @CustomerID; UPDATE [Sales].[Customer] SET YTDOrders = 0, YTDSales = 0 WHERE [CustomerID] = @CustomerID; -- place 3 orders for that customer EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 100, @OrderDate, @Status; EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 50, @OrderDate, @Status; EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 5, @OrderDate, @Status; COMMIT TRANSACTION
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspShowOrderDetailsTest를 클릭하고 인접한 목록에서 테스트를 클릭합니다.
시험 이전이 아니라 테스트에 체크섬 조건을 적용하려면 이 작업을 수행해야 합니다.
테스트 조건 창의 목록에서 데이터 체크섬를 클릭한 다음 테스트 조건 추가를 클릭합니다.
속성 창의 구성 속성에서 찾아보기 단추를 클릭합니다('...').
checksumCondition1에 대한 구성 대화 상자에서 데이터베이스에 대한 연결을 지정합니다.
대화 상자의 연결 편집 단추 아래에 있는 Transact-SQL을 다음 코드로 바꿉니다.
BEGIN TRANSACTION -- Add a customer for this test with the name 'CustomerB' DECLARE @NewCustomerID AS INT, @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @NewCustomerID = 0, @CustomerName = N'Fictitious Customer'; IF NOT EXISTS(SELECT * FROM [Sales].[Customer] WHERE CustomerName = @CustomerName) BEGIN EXECUTE @NewCustomerID = [Sales].[uspNewCustomer] @CustomerName; END DECLARE @CustomerID AS INT, @Amount AS INT, @OrderDate AS DATETIME, @Status AS CHAR (1); SELECT @RC = 0, @CustomerID = 0, @CustomerName = N'Fictitious Customer', @OrderDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- delete any old records in the Orders table and clear out the YTD Sales/Orders fields DELETE from [Sales].[Orders] WHERE [CustomerID] = @CustomerID; UPDATE [Sales].[Customer] SET YTDOrders = 0, YTDSales = 0 WHERE [CustomerID] = @CustomerID; -- place 3 orders for that customer EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 100, @OrderDate, @Status; EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 50, @OrderDate, @Status; EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 5, @OrderDate, @Status; COMMIT TRANSACTION -- ssNoVersion unit test for Sales.uspFillOrder DECLARE @FilledDate AS DATETIME; DECLARE @OrderID AS INT; SELECT @RC = 0, @CustomerID = 0, @OrderID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @FilledDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- fill an order for that customer EXECUTE @RC = [Sales].[uspShowOrderDetails] @CustomerID; SELECT @RC AS RC;
이 코드는 테스트 전의 Transact-SQL 코드를 테스트 자체의 Transact-SQL과 조합합니다. 둘 다 테스트가 실행할 때 반환하는 것과 동일한 결과를 반환해야 합니다.
검색을 클릭합니다. 필요한 경우 데이터가 표시될 때까지 검색을 클릭합니다.
지정한 Transact-SQL이 실행되고 반환된 데이터에 대해 체크섬이 계산됩니다.
확인을 클릭합니다.
계산된 체크섬은 테스트 조건과 함께 저장됩니다. 예상 체크섬이 데이터 체크섬 테스트 조건의 값 열에 표시됩니다.
파일 메뉴에서 모두 저장을 클릭합니다.
이제 테스트를 실행할 준비가 되었습니다.
SQL Server 단위 테스트 실행
SQL Server 단위 테스트를 실행하려면
테스트 메뉴에서 창을 가리킨 다음 Visual Studio 2010에서는 테스트 보기, Visual Studio 2012에서는 테스트 탐색기를 클릭합니다.
테스트 보기 창(Visual Studio 2010)의 도구 모음에서 새로 고침을 클릭하여 테스트 목록을 업데이트합니다. 테스트 탐색기(Visual Studio 2012)에서 테스트 목록을 보려면 솔루션을 빌드합니다.
테스트 뷰 또는 테스트 탐색기 창에는 이 연습의 초반에 만들었고 Transact-SQL 문 및 테스트 조건을 추가한 테스트가 나열됩니다. 이름이 TestMethod1인 테스트는 비어 있으며 이 연습에서 사용되지 않습니다.
Sales_uspNewCustomerTest를 마우스 오른쪽 단추로 클릭하고 선택 영역 실행을 클릭합니다.
Visual Studio는 지정한 권한 있는 컨텍스트를 사용하여 데이터베이스에 연결하고 데이터 생성 계획을 적용합니다. Visual Studio에서는 테스트에서 Transact-SQL 스크립트를 실행하기 전에 실행 컨텍스트로 전환합니다. 마지막으로 Visual Studio는 테스트 조건에서 지정한 것에 대해 Transact-SQL 스크립트를 평가하고 성공 또는 실패 결과가 테스트 결과 창에 표시됩니다.
테스트 결과 창에서 결과를 봅니다.
테스트가 성공합니다. 즉, 테스트를 실행할 때 SELECT 문이 한 개의 행을 반환합니다.
Sales_uspPlaceNewOrderTest, Sales_uspFillOrderTest 및 Sales_uspShowOrderDetailsTest 테스트에 대해 3단계를 반복합니다. 결과는 다음과 같습니다.
테스트 예상 결과 Sales_uspPlaceNewOrderTest 통과 Sales_uspShowOrderDetailsTest 통과 Sales_uspFillOrderTest "ScalarValueCondition 조건(scalarValueCondition2) 실패:ResultSet 1 Row 1 Column 1: 값이 일치하지 않으며 실제 '-100' 예상 '100'입니다." 오류와 함께 실패합니다. 이 오류는 저장 프로시저의 정의에 사소한 오류가 포함되어 있기 때문에 발생합니다. 다음으로 오류를 수정하고 테스트를 다시 실행합니다.
Sales.uspFillOrder에서 오류를 수정하려면
SQL Server 개체 탐색기의 데이터베이스에 대한 프로젝트 노드에서 uspFillOrder 저장 프로시저를 두 번 클릭하여 Transact-SQL 편집기에서 해당 정의를 엽니다.
정의에서 다음 Transact-SQL 문을 찾습니다.
UPDATE [Sales].[Customer] SET YTDSales = YTDSales - @Delta WHERE [CustomerID] = @CustomerID
다음 문과 일치하도록 문에서 SET 절을 변경합니다.
UPDATE [Sales].[Customer] SET YTDSales = YTDSales + @Delta WHERE [CustomerID] = @CustomerID
파일 메뉴에서 uspFillOrder.sql 저장을 클릭합니다.
테스트 보기에서 Sales_uspFillOrderTest를 마우스 오른쪽 단추로 클릭하고 선택 영역 실행을 클릭합니다.
테스트가 통과됩니다.
부정 단위 테스트 추가
부정 테스트를 만들어 테스트가 실패할 때 실패하는지 확인할 수 있습니다. 예를 들어 이미 채워진 주문을 취소하려고 하면 해당 테스트가 실패합니다. 연습의 이 부분에서는 Sales.uspCancelOrder 저장 프로시저에 대한 부정 단위 테스트를 만듭니다.
부정 테스트를 만들고 확인하려면 다음 작업을 수행해야 합니다.
저장 프로시저를 업데이트하여 오류 조건 테스트
새 단위 테스트를 정의합니다.
단위 테스트에 대한 코드를 수정하여 예상되는 실패를 나타냅니다.
단위 테스트를 실행합니다.
저장 프로시저를 업데이트하려면
SimpleUnitTestDB 데이터베이스의 SQL Server 개체 탐색기 프로젝트 노드에서 프로젝트 노드를 확장하고 프로그래밍 노드를 확장하고 저장 프로시저 노드를 확장하며 uspCancelOrder를 두 번 클릭합니다.
Transact-SQL 편집기에서 다음 코드와 일치하도록 프로시저 정의를 업데이트합니다.
CREATE PROCEDURE [Sales].[uspCancelOrder] @OrderID INT AS BEGIN DECLARE @Delta INT, @CustomerID INT, @PriorStatus CHAR(1) BEGIN TRANSACTION BEGIN TRY IF (NOT EXISTS(SELECT [CustomerID] from [Sales].[Orders] WHERE [OrderID] = @OrderID)) BEGIN -- Specify WITH LOG option so that the error is -- written to the application log. RAISERROR( 'That order does not exist.', -- Message text 16, -- severity 1 -- state ) WITH LOG; END SELECT @Delta = [Amount], @CustomerID = [CustomerID], @PriorStatus = [Status] FROM [Sales].[Orders] WHERE [OrderID] = @OrderID IF @PriorStatus <> 'O' BEGIN -- Specify WITH LOG option so that the error is -- written to the application log. RAISERROR ( 'You can only cancel open orders.', -- Message text 16, -- Severity 1 -- State ) WITH LOG; END ELSE BEGIN -- If we make it to here, then we can cancel the order. Update the status to 'X' first... UPDATE [Sales].[Orders] SET [Status] = 'X' WHERE [OrderID] = @OrderID -- and then remove the amount from the YTDOrders for the customer UPDATE [Sales].[Customer] SET YTDOrders = YTDOrders - @Delta WHERE [CustomerID] = @CustomerID COMMIT TRANSACTION RETURN 1; -- indicate success END END TRY BEGIN CATCH DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @ErrorSeverity INT; DECLARE @ErrorState INT; SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); ROLLBACK TRANSACTION -- Use RAISERROR inside the CATCH block to return -- error information about the original error that -- caused execution to jump to the CATCH block. RAISERROR (@ErrorMessage, -- Mesasge text @ErrorSeverity, -- Severity @ErrorState -- State ); RETURN 0; -- indicate failure END CATCH; END
파일 메뉴에서 uspCancelOrder.sql 저장을 클릭합니다.
F5 키를 눌러 SimpleUnitTestDB를 배포합니다.
업데이트를 uspCancelOrder 저장 프로시저에 배포합니다. 다른 개체는 변경하지 않았기 때문에 저장 프로시저만 업데이트됩니다.
다음으로 이 프로시저에 대한 연결된 단위 테스트를 정의합니다.
uspCancelOrder에 대한 SQL Server 단위 테스트를 작성하려면
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspCancelOrderTest를 클릭하고 인접한 목록에서 테스트가 강조 표시되어 있는지 확인합니다.
이 단계를 수행한 후 단위 테스트에서 테스트 작업에 대한 테스트 스크립트를 만들 수 있습니다.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
-- ssNoVersion unit test for Sales.uspFillOrder DECLARE @RC AS INT, @CustomerID AS INT, @Amount AS INT, @FilledDate AS DATETIME, @Status AS CHAR (1); DECLARE @CustomerName AS NVARCHAR(40), @OrderID AS INT; SELECT @RC = 0, @CustomerID = 0, @OrderID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @FilledDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- Get the most recently added order. SELECT @OrderID = MAX([OrderID]) FROM [Sales].[Orders] WHERE [CustomerID] = @CustomerID; -- try to cancel an order for that customer that has already been filled EXECUTE @RC = [Sales].[uspCancelOrder] @OrderID; SELECT @RC AS RC;
테스트 조건 창에서 결과 불충분 테스트 조건을 클릭하고 테스트 조건 삭제 아이콘을 클릭합니다.
테스트 조건 창에서 목록에서 스칼라 값을 클릭한 다음 테스트 조건 추가 아이콘을 클릭합니다.
속성 창에서 예상된 값 속성을 0으로 설정합니다.
SQL Server 단위 테스트 디자이너의 탐색 모음에서 Sales_uspCancelOrderTest를 클릭하고 인접한 목록에서 테스트 이전이 강조 표시되어 있는지 확인합니다. 이 단계를 수행한 후 테스트를 실행하는 데 필요한 상태로 데이터를 배치하는 문을 지정할 수 있습니다. 이 예제에서는 주문을 하기 전에 고객 레코드를 만들어야 합니다.
테스트 전 스크립트를 만들려면 여기를 클릭하여 만들기를 클릭하세요.
다음 문과 일치하도록 Transact-SQL 편집기에서 Transact-SQL 문을 업데이트합니다.
/* Add Transact-SQL statements here to run before the test script is run. */ BEGIN TRANSACTION -- Add a customer for this test with the name 'CustomerB' DECLARE @NewCustomerID AS INT, @RC AS INT, @CustomerName AS NVARCHAR (40); SELECT @RC = 0, @NewCustomerID = 0, @CustomerName = N'Fictitious Customer'; IF NOT EXISTS(SELECT * FROM [Sales].[Customer] WHERE CustomerName = @CustomerName) BEGIN EXECUTE @NewCustomerID = [Sales].[uspNewCustomer] @CustomerName; END DECLARE @CustomerID AS INT, @Amount AS INT, @OrderDate AS DATETIME, @FilledDate AS DATETIME, @Status AS CHAR (1), @OrderID AS INT; SELECT @RC = 0, @CustomerID = 0, @OrderID = 0, @CustomerName = N'Fictitious Customer', @Amount = 100, @OrderDate = getdate(), @FilledDate = getdate(), @Status = 'O'; -- NOTE: Assumes that you inserted a Customer record with CustomerName='Fictitious Customer' in the pre-test script. SELECT @CustomerID = [CustomerID] FROM [Sales].[Customer] WHERE [CustomerName] = @CustomerName; -- delete any old records in the Orders table and clear out the YTD Sales/Orders fields DELETE from [Sales].[Orders] WHERE [CustomerID] = @CustomerID; UPDATE [Sales].[Customer] SET YTDOrders = 0, YTDSales = 0 WHERE [CustomerID] = @CustomerID; -- place an order for that customer EXECUTE @OrderID = [Sales].[uspPlaceNewOrder] @CustomerID, @Amount, @OrderDate, @Status; -- fill the order for that customer EXECUTE @RC = [Sales].[uspFillOrder] @OrderID, @FilledDate; COMMIT TRANSACTION
파일 메뉴에서 모두 저장을 클릭합니다.
이제 테스트를 실행할 준비가 되었습니다.
SQL Server 단위 테스트를 실행하려면
테스트 보기에서 Sales_uspCancelOrderTest 마우스 오른쪽 단추로 클릭하고 선택 영역 실행을 클릭합니다.
테스트 결과 창에서 결과를 봅니다.
테스트가 실패하고 다음 오류가 나타납니다.
테스트 메서드 TestProject1.SqlServerUnitTests1.Sales_uspCancelOrderTest가 예외를 발생시켰습니다. System.Data.SqlClient.SqlException: 열려 있는 주문만 취소할 수 있습니다.
다음으로 예외가 예상된다고 나타내도록 코드를 수정합니다.
단위 테스트에 대한 코드를 수정하려면
솔루션 탐색기에서 TestProject1을 확장하고 SqlServerUnitTests1.cs를 마우스 오른쪽 단추로 클릭한 다음 코드 보기를 클릭합니다.
코드 편집기에서 Sales_uspCancelOrderTest 메서드로 이동합니다. 다음 코드와 일치하도록 메서드의 특성을 수정합니다.
[TestMethod(), ExpectedSqlException(Severity=16, MatchFirstError=false, State=1)] public void Sales_uspCancelOrderTest()
특정 예외가 표시되도록 지정합니다. 필요에 따라 특정 오류 번호를 지정할 수 있습니다. 이 특성을 추가하지 않으면 단위 테스트가 실패하고 메시지가 테스트 결과 창에 표시됩니다.
Important
현재 Visual Studio 2012는 ExpectedSqlException 특성을 지원하지 않습니다. 이 작업에 대한 자세한 내용은 "예상된 실패" 데이터베이스 단위 테스트를 실행할 수 없음을 참조하세요.
파일 메뉴에서 SqlServerUnitTests1.cs 저장을 클릭합니다.
다음으로 단위 테스트를 다시 실행하여 예상대로 실패했는지 확인합니다.
SQL Server 단위 테스트를 다시 실행하려면
테스트 보기에서 Sales_uspCancelOrderTest 마우스 오른쪽 단추로 클릭하고 선택 영역 실행을 클릭합니다.
테스트 결과 창에서 결과를 봅니다.
테스트가 통과이며, 프로시저가 실패해야 할 때 실패했다는 의미입니다.
다음 단계
일반적인 프로젝트에서는 모든 중요한 데이터베이스 개체가 올바르게 작동하는지 확인하기 위해 추가 단위 테스트를 정의합니다. 테스트 집합이 완료되면 해당 테스트를 버전 제어로 체크 인하여 팀과 공유합니다.
기준을 설정한 후 데이터베이스 개체를 만들고 수정한 다음 연결된 테스트를 만들어 변경으로 예상된 동작이 중단되는지 여부를 확인할 수 있습니다.
참고 항목
SQL Server 단위 테스트 만들기 및 정의
SQL Server 단위 테스트를 사용하여 데이터베이스 코드 확인
방법: 빈 SQL Server 단위 테스트 만들기
방법: SQL Server 단위 테스트 실행 구성