Пошаговое руководство. Создание и запуск модульного теста SQL Server
В этом пошаговом руководстве будет создан модульный тест SQL Server, который проверяет работу нескольких хранимых процедур.Модульные тесты 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/2020')); 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/2020')); 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); SELECT 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.
Установите флажок Создать каталог для решения, если он еще не установлен.
Снимите флажок Добавить к системе управления версиями, если он еще не снят, затем нажмите кнопку ОК.
Проект базы данных будет создан и отображен в обозревателе решений.Далее нужно импортировать схему базы данных из скрипта.
Импорт схемы базы данных из скрипта
В меню Project выберите Импорт, а затем — Скрипт (*.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.Далее нужно обновить логику тестов в скрипте Transact-SQL модульных тестов.
Определение логики тестов
В этой очень простой базе данных есть две таблицы — Customer и Order.Нужно обновить базу данных с помощью следующих хранимых процедур.
uspNewCustomer — эта хранимая процедура добавляет запись в таблицу Customer, которая задает нулевые значения для столбцов YTDOrders и YTDSales.
uspPlaceNewOrder — эта хранимая процедура добавляет запись в таблицу Orders для указанного заказчика и обновляет значение YTDOrders соответствующей записи в таблице Customer.
uspFillOrder — эта хранимая процедура обновляет запись в таблице Orders путем изменения состояния с «О» на «F» и увеличивает сумму YTDSales для соответствующей записи в таблице Customer.
uspCancelOrder — эта хранимая процедура обновляет запись в таблице Orders путем изменения состояния с «О» на «X» и уменьшает сумму YTDOrders для соответствующей записи в таблице Customer.
uspShowOrderDetails — эта хранимая процедура объединяет таблицу Orders с таблицей Custom и выводит записи для определенного заказчика.
Примечание |
---|
|
Предполагается, что база данных в тестах начинает работу в чистом состоянии.Необходимо создать тесты, которые будут проверять следующие условия.
uspNewCustomer — проверяет, чтобы таблица Customer содержала одну строку после запуска хранимой процедуры.
uspPlaceNewOrder — для заказчика, у которого поле CustomerID имеет значение 1, размещает заказ на 100 долларов.Убедитесь, что сумма YTDOrders для этого заказчика равна 100, а сумма YTDSales — нулю.
uspFillOrder — для заказчика, у которого поле CustomerID имеет значение 1, размещает заказ на 50 долларов.Заполните этот заказ.Убедитесь, что суммы YTDOrders и YTDSales обе равны 50.
uspShowOrderDetails — для заказчика, у которого поле CustomerID имеет значение 1, размещает заказы на 100, 50 и 5 долларов.Убедитесь, что uspShowOrderDetails возвращает нужное число столбцов и что результирующий набор имеет ожидаемую контрольную сумму.
Примечание |
---|
|
Запись модульного теста SQL Server для хранимой процедуры uspNewCustomer
На панели навигации в конструкторе модульных тестов 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];
На панели Условия теста щелкните условие теста «С неопределенным результатом» и затем щелкните значок Удалить условие теста (красный знак Х).
На панели Условия теста щелкните в списке пункт Счетчик строк, а затем щелкните значок Добавить условие теста (зеленый знак +).
Откройте окно Свойства (выберите условие теста и нажмите клавишу F4) и задайте свойству Число строк значение 1.
В меню Файл выберите команду Сохранить все.
Далее нужно определить логику модульного теста для хранимой процедуры uspPlaceNewOrder.
Запись модульного теста SQL Server для хранимой процедуры uspPlaceNewOrder
На панели навигации в конструкторе модульных тестов 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 и убедитесь, что в смежном списке выделен пункт Перед тестом.
После выполнения этого шага можно указать инструкции, которые переведут данные в состояние, необходимое для выполнения теста.В этом примере, прежде чем размещать заказ, необходимо создать запись Customer.
Щелкните Щелкните здесь, чтобы создать и создайте скрипт, который будет выполняться перед тестом.
Обновите инструкции 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.
Запись модульного теста SQL Server для хранимой процедуры uspFillOrder
На панели навигации в конструкторе модульных тестов 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 и убедитесь, что в смежном списке выделен пункт Перед тестом.После выполнения этого шага можно указать инструкции, которые переведут данные в состояние, необходимое для выполнения теста.В этом примере, прежде чем размещать заказ, необходимо создать запись Customer.
Щелкните Щелкните здесь, чтобы создать и создайте скрипт, который будет выполняться перед тестом.
Обновите инструкции 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
В меню Файл выберите команду Сохранить все.
Запись модульного теста SQL Server для хранимой процедуры uspShowOrderDetails
На панели навигации в конструкторе модульных тестов 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 и убедитесь, что в смежном списке выделен пункт Перед тестом.После выполнения этого шага можно указать инструкции, которые переведут данные в состояние, необходимое для выполнения теста.В этом примере, прежде чем размещать заказ, необходимо создать запись Customer.
Щелкните Щелкните здесь, чтобы создать и создайте скрипт, который будет выполняться перед тестом.
Обновите инструкции 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, после чего для полученных данных вычисляется контрольная сумма.
Нажмите кнопку ОК.
Вычисленная контрольная сумма сохраняется в условии теста.Ожидаемая контрольная сумма появляется в столбце Value условия теста «Контрольная сумма данных».
В меню Файл выберите команду Сохранить все.
Теперь все готово для запуска тестов.
Выполнение модульных тестов 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 при выполнении возвращает одну строку.
Повторите шаг 3 для тестов Sales_uspPlaceNewOrderTest, Sales_uspFillOrderTest и Sales_uspShowOrderDetailsTest.Результаты должны быть следующими.
Тест Ожидаемый результат Sales_uspPlaceNewOrderTest Успех Sales_uspShowOrderDetailsTest Успех Sales_uspFillOrderTest Завершается со следующей ошибкой: "Условие ScalarValueCondition (scalarValueCondition2) выполнить не удалось: ResultSet 1 Строка 1 Столбец 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
В меню Файл выберите команду Save 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
В меню Файл выберите команду Save uspCancelOrder.sql.
Нажмите клавишу F5, чтобы развернуть SimpleUnitTestDB.
Необходимо развернуть обновления хранимой процедуры uspCancelOrder.Обновляется только хранимая процедура, другие объекты не изменяются.
Далее нужно определить связанный модульный тест для этой процедуры.
Запись модульного теста SQL Server для процедуры uspCancelOrder
На панели навигации в конструкторе модульных тестов 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 и убедитесь, что в смежном списке выделен пункт Перед тестом.После выполнения этого шага можно указать инструкции, которые переведут данные в состояние, необходимое для выполнения теста.В этом примере, прежде чем размещать заказ, необходимо создать запись Customer.
Щелкните Щелкните здесь, чтобы создать и создайте скрипт, который будет выполняться перед тестом.
Обновите инструкции 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 правой кнопкой мыши и выберите Выполнить выбранное.
Просмотрите результаты в окне Результаты теста.
Тест завершается следующей ошибкой.
Test method TestProject1.SqlServerUnitTests1.Sales_uspCancelOrderTest threw exception: System.Data.SqlClient.SqlException: You can only cancel open orders.
Далее необходимо изменить код и указать, что исключение является ожидаемым.
Изменение кода модульного теста
В обозревателе решений разверните TestProject1, щелкните SqlServerUnitTests1.cs правой кнопкой мыши и выберите Просмотр кода.
В редакторе кода найдите метод Sales_uspCancelOrderTest.Измените атрибуты метода так, чтобы он совпадал со следующим кодом:
[TestMethod (), ExpectedSqlException (Severity=16, MatchFirstError=false, State=1)] public void Sales_uspCancelOrderTest ()
Необходимо указать, что ожидается определенное исключение.Можно дополнительно указать номер ошибки.Если не добавить этот атрибут, модульный тест завершится ошибкой и в окне «Результаты теста» появится сообщение.
Важно!
В настоящее время Visual Studio 2012 не поддерживает атрибут ExpectedSqlException.Сведения о том, как обойти это ограничение, см. в разделе Невозможно выполнить модульный тест базы данных типа «Ожидаемый сбой».В меню «Файл» выберите команду «Сохранить SqlServerUnitTests1.cs».
Далее необходимо повторно выполнить модульный тест, чтобы убедиться, что он завершается ожидаемой ошибкой.
Повторное выполнение модульных тестов SQL Server
В окне Представление теста щелкните процедуру Sales_uspCancelOrderTest правой кнопкой мыши и выберите Выполнить выбранное.
Просмотрите результаты в окне Результаты теста.
Тест выполнен, то есть хранимая процедура завершилась ошибкой в нужном участке кода.
Следующие действия
В типовом проекте обычно определяются дополнительные модульные тесты для проверки исправной работы всех важнейших объектов базы данных.Когда набор тестов задан, эти тесты заносятся в систему управления версиями и делаются доступными другим участникам группы.
После определения основы можно приступить к созданию и изменению объектов базы данных, а затем создать связанные тесты и проверить, влияют ли изменения на ожидаемое поведение.
См. также
Создание и определение модульных тестов SQL Server
Проверка кода базы данных с помощью модульных тестов SQL Server
Практическое руководство. Создание пустого модульного теста SQL Server
Практическое руководство. Настройка запуска модульного теста SQL Server