Проектирование и реализация стратегии тестирования
Проект базы данных SQL, успешно собранный, не означает, что хранимые процедуры возвращают правильные результаты. Процедура может компилироваться без ошибок и по-прежнему вычислять неправильные итоги или пропускать проверку. Тестирование перехватывает эти проблемы, прежде чем они достигают рабочей среды.
Общие сведения о уровнях тестирования базы данных
Тестирование базы данных работает на уровнях, каждый из которых перехватывает другой класс проблем:
-
Проверка сборки
dotnet build— это шаг, который у вас уже есть. Он перехватывает синтаксические ошибки и неисправные ссылки на объекты. Быстро, но это только подтверждает, что схема является структурно допустимой. - Модульные тесты проверяют, что отдельные хранимые процедуры и функции создают правильные результаты для заданного набора входных данных. Они обнаруживают ошибки логики.
- Тесты интеграции используют комплексные сценарии для развернутой базы данных. Они доказывают, что объекты работают правильно, но для этого требуется экземпляр в работе, и это занимает самое большее время.
Каждый слой медленнее и дороже, чем тот, что перед ним, но также выявляет проблемы, которые предыдущий слой не может обнаружить.
Создание модульных тестов SQL Server
SQL Server Data Tools (SSDT) в Visual Studio включает встроенную платформу для модульных тестов базы данных. Каждый тест выполняет T-SQL в динамической базе данных и проверяет результаты с помощью условий тестирования.
Структура модульного теста
Каждый тест содержит три раздела, которые соответствуют шаблону установки-выполнения и очистки:
- Предварительный тест: настройте данные, необходимые для тестирования. Добавьте записи клиентов, очистите оставшиеся данные из предыдущих запусков.
- Тест: выполните операцию, которую вы тестируете. Вызовите хранимую процедуру и запросите представление.
- После теста: очистка после теста, чтобы он не загрязнял следующий запуск.
Условия тестирования
После запуска тестового T-SQL условия тестирования используются для проверки возвратившихся данных. Наиболее часто используются условия:
- Число строк: проверяет, содержит ли результирующий набор ожидаемое количество строк.
- Скалярное значение: проверяет, содержит ли определенная ячейка в результирующем наборе ожидаемое значение.
- Ожидаемая схема: проверяет, имеет ли результирующий набор ожидаемые имена столбцов и типы данных.
К другим встроенным условиям относятся контрольная сумма данных, пустой результирующий набор, не пустой результирующий набор и время выполнения.
Создание проекта модульного теста
Настройка модульных тестов SQL Server в Visual Studio требует выполнения нескольких шагов.
- Откройте проект базы данных SQL.
- В обозревателе объектов SQL Server найдите хранимую процедуру или функцию, которую вы хотите проверить.
- Щелкните объект правой кнопкой мыши и выберите "Создать модульные тесты".
- Выберите или создайте тестовый проект C#.
- Задайте тестовое подключение к базе данных разработки.
- Выберите параметр Автоматически развернуть проект базы данных перед запуском модульных тестов. Этот параметр обеспечивает синхронизацию тестовой базы данных с последними изменениями проекта.
Конструктор открывается с помощью шаблона T-SQL, в котором выполняется запись логики тестирования и присоединение условий теста.
Написание эффективных модульных тестов базы данных
Хороший модульный тест отвечает на конкретный вопрос: "Выполняет ли эта процедура то, что она должна делать при известных входных данных?" Ниже приведен пример, который тестирует uspPlaceNewOrder, проверяя, что размещение заказа правильно обновляет годовую итоговую сумму клиента.
-- Pre-test: Set up customer and clear previous data
DECLARE @CustomerID INT;
INSERT INTO [Sales].[Customer] (CustomerName) VALUES (N'Test Customer');
SET @CustomerID = SCOPE_IDENTITY();
DELETE FROM [Sales].[Orders] WHERE [CustomerID] = @CustomerID;
-- Test: Place an order and verify YTDOrders updated correctly
DECLARE @RC INT;
EXECUTE @RC = [Sales].[uspPlaceNewOrder] @CustomerID, 100, GETDATE(), 'O';
SELECT [YTDOrders]
FROM [Sales].[Customer]
WHERE [CustomerID] = @CustomerID;
📝Свяжите этот тест T-SQL с условием теста скалярного значения, который ожидает, что YTDOrders значение будет 100.
Отрицательные тесты
Кроме того, необходимо убедиться, что хранимые процедуры выдают ошибку при получении недопустимых входных данных. Например, отмена заказа, который уже отправлен, должна вызвать ошибку, а не произойти без уведомления. Отрицательный тест подтверждает, что произошла ожидаемая ошибка.
При выборе команды "Создать модульные тесты " на шаге 3 предыдущего раздела Visual Studio создает тестовый проект C# в обозревателе решений с .cs файлом, содержащим тест для каждой выбранной хранимой процедуры. Например, если вы создали тест для uspCancelOrder, созданный файл содержит раздел с именем Sales_uspCancelOrder_Test. Чтобы пометить этот тест как отрицательный тест, откройте .cs файл в обозревателе решений и добавьте ExpectedSqlException атрибут непосредственно над ним и сохраните файл:
[TestMethod()]
[ExpectedSqlException(Severity = 16, MatchFirstError = false, State = 1)]
public void Sales_uspCancelOrder_FilledOrder_Test()
Тест проходит только в том случае, если хранимая процедура вызывает ошибку, соответствующую заданной серьезности и состоянию. Если процедура выполняется без уведомлений об ошибках, тест завершается сбоем, что именно и требуется.
Разработка подхода к тестированию интеграции
Модульные тесты изолируют отдельные объекты. Тесты интеграции идут дальше и тестируют сценарии, охватывающие несколько операций. Они отвечают на такие вопросы:
- Последовательность вызовов хранимой процедуры оставляет базу данных в ожидаемом состоянии?
- Активируются ли триггеры корректно с поступлением данных через уровень приложения?
- Возвращают ли представления точные результаты после ряда связанных изменений таблицы?
Для тестов интеграции требуется выделенная база данных. Разверните проект базы данных SQL в тестовом экземпляре перед каждым запуском с помощью автоматического развертывания проекта базы данных перед выполнением модульных тестов . Этот параметр сохраняет текущую схему тестирования.
Рекомендации по тестированию баз данных
Модульные тесты и тесты интеграции запускают T-SQL в динамической базе данных, поэтому тестовая среда нуждается в тщательной настройке для получения надежных результатов.
- Изоляция тестов от рабочей среды. Используйте отдельный экземпляр или выделенную тестовую базу данных. Проведение тестов в продакшн среде никогда не рекомендуется.
- Сбросьте в известное состояние перед каждым запуском. Скрипты после развертывания или скрипты очистки после тестирования обрабатывают эту проблему.
- Вынесите строки подключения в конфигурационных файлах, чтобы локальная разработка и конвейеры CI использовали правильную базу данных без изменений в коде.
Интеграция тестов в конвейеры CI/CD
Добавьте тестовый шаг после сборки и развертывания, чтобы тесты выполнялись автоматически при каждом коммите. В Azure DevOps используйте VSTest задачу:
- task: VSTest@2
inputs:
testAssembly: '**\*Tests.dll'
searchFolder: '$(System.DefaultWorkingDirectory)'
В GitHub Actions выполните тесты с помощью dotnet test:
- name: Run database unit tests
run: dotnet test ./DatabaseTests/DatabaseTests.csproj
Подсказка
Настройте тестовый проект для автоматического развертывания проекта базы данных перед выполнением тестов. Этот параметр гарантирует, что схема тестовой базы данных соответствует проекту во время тестирования.
Если тест завершается сбоем, конвейер останавливается, а изменение не достигает промежуточной или рабочей среды. Эта задержка дает команде время для устранения проблемы, прежде чем она влияет на любую среду.
Основные выводы
Тестирование базы данных охватывает три уровня: проверка сборки для структурной правильности, модульные тесты для проверки логики и тесты интеграции для сквозных рабочих процессов. Модульные тесты SQL Server следуют трехфазной структуре: подготовительные действия, тестовые действия и действия после тестирования. Чтобы проверить хранимую процедуру и поведение функции, используйте такие условия теста, как Scalar Value, Row Countи Expected Schema. Чтобы проверить методы, которые должны проверять пути обработки ошибок, добавьте ExpectedSqlException атрибут. Интегрируйте тестовые проекты в ваш конвейер CI/CD, чтобы неудачные тесты блокировали развертывание, прежде чем изменения попадут в стейджинг или продакшн. Вместе эти три уровня формируют сеть безопасности, которая позволяет команде развертывать изменения базы данных с уверенностью вместо тревоги.