Тестирование базы данных. Версия разработчика

в 9:10, , рубрики: eclipse, sql, тестирование, Тестирование IT-систем

Несколько лет занимаюсь программированием баз данных и столько же вижу как непросто идет тестирование функционала, реализованного в самой базе. Такая задача требует от тестировщика не только знаний SQL, но, порой, и понимания тонкостей работы тестируемого функционала. А разработчики не всегда стремятся описать свое решение во всех деталях.

Стало интересно — как сейчас тестируется логика базы данных. Думаю, неудивительно, что на тот момент поиски в интернете успехом не увенчались. То ли из-за недостаточной настойчивости, то ли из-за желания сделать «такое же, но свое, другое». А имеющиеся варианты не устраивали из-за сложности использования. Например, были и clr-сборки с unit-тестами. Про HP QTP узнал уже позже.

И эта деятельность привела к созданию конструктора тестов, воплотившегося в плагине к eclipse для тестирования базы. В статье будут описаны основы работы с конструктором.

Не хочу теорию, хочу сразу результат!

Теория

В основу алгоритма вошли принципы:

  • тест состоит из последовательности шагов (простых sql-скриптов)
  • шаг — это единичная операция, принимающая одни данные на вход и возвращающая другие
  • шаги можно объединять в последовательность для создания более сложного модуля
  • меньше кода при создании теста, больше работы мышкой
  • тесты будут храниться в базе

И как бы я, будучи тестировщиком, хотел бы создавать тесты:

  1. Я хочу 1 раз написать простой скрипт, дать ему название, задать параметры, и сохранить для повторного использования. И пусть программа сама находит параметры из текста скрипта. А я уж задам им тип данных и направление — входной это параметр или выходной.
  2. Хочу объединять несколько скриптов в один компонент. Допустим, нужно положить запись в базу, дождаться её обработки и получить результат этой обработки. Компонент — основная логическая единица для создания теста.
  3. И пусть компоненты можно будет объединять в сам тест. Тот самый, который и будет проверять ту или иную бизнес-операцию.

Хорошо, с этим понятно. А где же проверка? Ведь результат теста — это сравнение ожидаемого и фактического результатов. Поэтому, и компонент и тест хранят для своих параметров контекст (подробнее и с примером ниже), который и укажет — это ожидаемое или эталонное значение. При этом, параметры должны быть с одинаковым именами. И, когда в работе компонента или теста произойдет изменение значения такого параметра, должна выполниться проверка на равенство или неравенство этих значений. Если проверка не прошла, весь тест завершится неуспешно.

Что из этого получилось

  1. Установка и настройка
  2. Создание проекта
  3. Создание скрипта
  4. Объединение скриптов в компонент
  5. Создание теста из компонентов

Установка и настройка

Плагин умеет работать с MS SQL Server.

  1. ссылка на плагин к eclipse и исходники в конце статьи. Ставим плагин
  2. создаем пустую базу и выполняем на ней скрипт из репозитория (databasescript.sql)
  3. Задаем в настройках 2 базы — для хранения тестов и для выполнения тестов (Window Preferences Настройки SQL тестов)

Настройка баз

Тестирование базы данных. Версия разработчика - 1

Создание проекта

File -> New -> Test -> SQL Test Project
Тестирование базы данных. Версия разработчика - 2

Выбираем настроенные базы и задаем пароли. По завершении жмем «Проверить введенные параметры». Если проверки пройдут успешно, станет доступной кпопка Finish. Жмем её для завершения создания проекта.

Тестирование базы данных. Версия разработчика - 3

По умолчанию нужная view не открывается, делаем это руками: Window -> Show View -> Other -> SQL Test Project Explorer. Созданный проект предстанет в таком виде:

Тестирование базы данных. Версия разработчика - 4

Создание скрипта

Для порядка, через контекстное меню на разделе «Скрипты» создадим папку «Пример», в которой и будут лежать наши примеры. И создадим через контекстное меню на папке «Пример» скрипт «Получить серверное время», который вернет дату и время сервера. Откроем папку «Пример» и, двойным кликом, откроем скрипт. Впишем этот текст скрипта и нажмем кнопку «Найти параметры».

SELECT GETDATE() AS [:NOW]

Параметры находятся по сигнатуре :param. А, чтобы получить значение из скрипта, следует вернуть DataSet с названием колонки — именем параметра [:param].

Выберем параметру тип DATE и направление «Выходной». Сохраняем скрипт и ждем рядом кнопку «Выполнить». В колонке «Тестовое значение» отобразится результат:

Скрипт в окне

Тестирование базы данных. Версия разработчика - 5

Это простой пример. Теперь усложним задачу. Нам предстоит в тесте подождать 5 секунд, а потом убедиться, что мы выполнялись ровно 5 секунд. Это довольно искусственная задача, но для понимания возможностей самый раз.

Для решения задачи нам предстоит сделать несколько скриптов, чтобы потом объединить в компонент. Вот эти скрипты:

  1. Задать эталонный интервал в 5 секунд
  2. Получить серверное время #1
  3. Дождаться истечения 5 секунд
  4. Получить серверное время #2
  5. Сравнить времена и убедиться, что разница составляет 5 секунд

Для (2) и (4) шагов у нас уже есть скрипт. (3) оставим на последок как наиболее сложный. Простой WAITFOR DELAY мы не будем использовать, так как это может быть любая длительная операция, которая может завершиться в любой момент времени, а не по истечении фиксированного интервала.

(1) может выглядеть совсем просто. Единственный параметр выходной, типа INTEGER:

SELECT 5 as [:interval]

И (5) так же не сложно. Первые два параметра будут входными, типа DATE. Третий — выходной, типа INTEGER:

SELECT DATEDIFF(SECOND, :from, :to) as [:interval]

Настал черед (3) скрипта, задача которого отработать быстро и сообщить — выполнилось ли условие и можно идти дальше, или повторить его выполнение чуть позже.

SELECT 1 as [:ret]
WHERE DATEDIFF(SECOND, :from, GETDATE()) >= :interval

Этот скрипт в "ret" вернет единицу, если количество секунд с момента :from по текущий момент не меньше параметра «interval», и ничего не вернет в ином случае. Вот это и будем проверять.

Выбираем тип скрипта «Событие», в выпадающем списке «Параметр» выбираем «ret», и в поле «Значение параметра» впишем 1. Программа будет выполнять скрипт этого типа, пока «ret» не станет равным 1. Повторный запуск будет через 100мс после завершения.

Скрипт: ждем завершение таймаута

Тестирование базы данных. Версия разработчика - 6

Вот мы и подошли к объединению созданных скриптов в компонент, в котором и будет выполняться проверка на равенство ожидаемого и фактического интервалов.

Объединение скриптов в компонент

По аналогии с созданием скриптов, создадим и откроем компонент «Проверить интервал». Перетащим в область «Скрипты» окна компонента мышкой из списка скриптов (в Project Explorer) созданные только что скрипты. Если перенесли что-то лишнее, кликаем мышкой и жмем кнопку «Удалить». У меня получилась такая последовательность скриптов:

  1. Задать эталонный интервал
  2. Получить серверное время
  3. Дождаться завершения таймаута
  4. Получить серверное время
  5. Получить разницу во времени

В разделе «Параметры» открытого компонента добавим 4 новых параметра:

Параметр Контекст Комментарий
interval Эталон Ожидаемое значение. Будет получено из (1) скрипта
interval Тест Фактическое значение. Будет получено из (5) скрипта
start Локальный Время начала теста. Будет получено из (2) скрипта
finish Локальный Время завершения теста. Будет получено из (4) скрипта

Осталось задать соответствие между параметрами компонента и перенесенных скриптов. Для этого кликаем на первый скрипт «Задать эталонный интервал» в списке скриптов. В таблице «Параметры скрипта» выделяем параметр «interval» и, через контекстное меню мышки, задаем связь с параметром компонента: Эталонinterval.

Связываем параметры скрипта и компонента

Тестирование базы данных. Версия разработчика - 7

Аналогично устанавливаем связи и для оставшихся скриптов

Параметр С чем связан
Получить серверное время
NOW [Локальный] start
Дождаться завершения таймаута
ret пропускаем
from [Локальный] start
interval [Эталон] interval
Получить серверное время
NOW [Локальный] finish
Получить разницу во времени
from [Локальный] start
to [Локальный] finish
interval [Тест] interval

Сохраняем компонент. У меня получился вот такой результат.

Итоговый вид компонента

Тестирование базы данных. Версия разработчика - 8

Перед запуском компонент должен быть сохранен, так как программа перед запуском его подгружает из базы. Нажимаем кнопку «Запустить» в окне компонента. Откроется новое окно с результатом теста, если оно не было открыто ранее.

Результат выполнения теста

Тестирование базы данных. Версия разработчика - 9

В данном результате отображены все данные по работе компонента: какие скрипты выполнялись, какие данные пришли на вход и получились на выходе. Если было сравнение параметров, то, как в нашем случае, оно тоже показано.

Попробуем «поломать» тест и посмотрим, как это отобразится. Изменим скрипт «Получить разницу во времени» на

SELECT DATEDIFF(SECOND, :from, :to) + 1 as [:interval]

Вернем на 1 больше, чем должно быть. Сохраним скрипт и снова запустим компонент.

Результат выполнения компонента

Тестирование базы данных. Версия разработчика - 10

Открыв детали, при должной сноровке можно даже найти место ошибки:

Тестирование базы данных. Версия разработчика - 11

Не забудем вернуть корректное значение запроса «Получить разницу во времени».

Контексты параметров

Название Значение
Глобальный Глобальная область видимости. Переменная компонента с этим контекстом доступна и вне компонента, в тесте например. При отлаживании компонента, в такой переменной можно задавать значение в колонке «Тестовое значение» таблицы «Параметры»
Локальный Локальная переменная. Вне компонента её не видно
Тест Тестовое значение. По аналогии с глобальной
Эталон Эталонное значение. По аналогии с глобальной

Создание теста из компонентов

Тест строится из компонентов точно так же, как и компонент из скриптов. Поэтому не буду подробно его описывать. Сделаем тест «Проверка интервалов» и перетащим в него 2 раза компонент «Проверить интервал». Сохраним и запустим тест.

Результат выполнения теста

Ожидаемый результат:

Тестирование базы данных. Версия разработчика - 12

Заключение

В данной статье описан простейший, искусственный сценарий для теста базы. Но нет ничего сложного и в реальных сценариях, где надо сохранить данные в базу, дождаться их обработки, и получить результат, сравнив с эталоном. Мне было интересно — получится ли убрать рутину ручного труда при создании и выполнении тестов в такой, весьма специфический области. Думаю, отчасти была решена эта задача. И для меня это был опыт знакомства с java и eclipse plugin development. Пусть это и еще один велосипед во всеобщий велопарк.

Ссылки

GoogleDrive: Плагин для eclipse (проверено на eclipse 4.5)
Проект плагина на GitHub

Автор: laminy

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js