Модульное тестирование хранимых процедур

44

Я долго обдумывал это.

Основной вопрос: как провести модульное тестирование хранимых процедур?

Я вижу, что я могу относительно легко настроить модульные тесты для функций в классическом смысле (я имею в виду, что они получают ноль или более аргументов и возвращают значение). Но если я рассмотрю реальный пример, казалось бы, простой процедуры, вставляющей строку куда-нибудь, с несколькими триггерами, делающими это и то, что до или после вставки, даже определение границ «единицы» довольно сложно. Должен ли я проверить только INSERTсам? Это довольно просто, я думаю, с относительно низкой стоимостью. Должен ли я проверить результат всей цепочки событий? Помимо вопроса, является ли это модульным тестом, разработка подходящего теста может быть довольно напряженной работой с множеством дополнительных вопросительных знаков, возникающих на пути.

И тогда возникает проблема постоянно меняющихся данных. В случае UPDATEзатрагивания нескольких строк, каждая потенциально затронутая строка должна быть как-то включена в тестовые примеры. Дальнейшие трудности с DELETEс и тд и тд.

Итак, как вы тестируете свои хранимые процедуры? Есть ли порог сложности, когда он становится совершенно безнадежным? Какие ресурсы необходимы для обслуживания?

РЕДАКТИРОВАТЬ Еще один маленький вопрос, основанный на ответе Алексея Кузнецова: или есть ли порог, под которым он совершенно бесполезен?

Dezso
источник

Ответы:

32

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

Я написал статью под названием « Закрыть эти лазейки: уроки, извлеченные из модульного тестирования T-SQL» , а также некоторые сообщения в блоге.

Что касается вашего вопроса «Есть ли порог сложности, когда он становится совершенно безнадежным?», Сложные модули нуждаются в тестах гораздо больше, чем простые.

Чтобы упростить обслуживание, мы генерируем ожидаемые результаты и храним их в отдельных файлах - это имеет огромное значение.

Аляска
источник
15

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

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

Изменение данных делает тестирование более трудным, но это не делает тестирование менее важным и фактически увеличивает ценность модульного тестирования, поскольку большинство трудностей нужно продумывать только один раз, а не каждый раз, когда в устройство вносятся изменения. Сохраненные наборы данных, вставки / обновления / удаления, которые являются частью настройки / разрыва, и операция с узкой областью действия - все это может быть использовано для облегчения этого. Поскольку вопрос не относится к базе данных, детали могут отличаться.

Не существует порога сложности на верхнем или нижнем конце, который должен мешать вам тестировать или модульное тестирование. Рассмотрим эти вопросы:

  1. Вы всегда пишете код без ошибок?
  2. Маленькие юниты всегда без ошибок?
  3. Это нормально для большой единицы, чтобы иметь ошибку?
  4. Сколько ошибок нужно, чтобы вызвать катастрофу?

Предположим, вы начинаете новую работу, и вам поручено оптимизировать небольшую функцию, используемую во многих местах. Вся заявка была написана и поддерживается сотрудником, которого никто даже не помнит. У единиц есть документация, описывающая нормальное ожидаемое поведение, но немного больше. Что из этого вы бы предпочли найти?

  • Никаких модульных тестов нигде в приложении. После внесения изменений вы можете провести некоторое ручное тестирование самого устройства, чтобы убедиться, что оно по-прежнему возвращает ожидаемые значения в документации. Затем вы можете развернуть его в производство, скрестить пальцы и надеяться, что он работает (в конце концов, вы всегда пишете безошибочный код, а оптимизация в одном блоке никогда не повлияет на другой) или потратить огромное количество времени на изучение работы всего приложения. работает так, что вы можете вручную проверить каждую единицу прямо или косвенно.
  • Модульные тесты во всем приложении, которые запускаются автоматически ежедневно или по запросу. Они проверяют не только нормальные входные значения и их ожидаемый отклик, но также ненормальные значения и ожидаемые исключения, которые возникают. Вы вносите изменения и запускаете пакет модульных тестов для приложения, сразу же увидев, что три других модуля больше не дают ожидаемых результатов. Два из них доброкачественные, так что вы настраиваете модульные тесты, чтобы учесть это. Третий требует еще одного небольшого изменения и небольшого нового модульного теста. После внесения изменений весь набор тестов завершается успешно, и вы с уверенностью внедряете изменения.
Ли Риффель
источник
1
Во-первых, спасибо за ваш ответ - я не ожидал дальнейшего продвижения по этому вопросу ... Во-вторых, я должен признать, что вы правы в отношении простых операций: даже INSERT с двумя столбцами может привести к ошибке. Если он написан так, что порядок столбцов можно сопоставить с аргументами, тогда все может быть в порядке, но тогда вы правы, опять же: вероятно, лучше держать все приложение в режиме тестирования.
Дезсо,
@dezso Это отличный вопрос и концепция, которая нуждается в гораздо большем освещении в мире баз данных.
Ли Риффель
«Вы должны проверить всю цепочку событий как единое целое» - это самая нелогичная вещь, которую вы могли бы сказать. Это не единица, если это так. Вы проводите интеграционное тестирование
Джо Филлипс
@Joe Philips - Назовите это как хотите, убедившись, что процедура, которая выполняет вставку и запускает несколько триггеров, выполняет то, что, как предполагается, требует автоматических тестов.
Ли Риффель
8

Для PostgreSQL, проверьте pgTAP :

pgTAP - это набор функций базы данных, которые облегчают написание модульных тестов, генерирующих TAP, в сценариях psql или в функциях тестирования в стиле xUnit.

Фрэнк Хейкенс
источник
Видел это, спасибо. Кто-нибудь сталкивался с этим?
Дезсо
Да, довольно много людей в настоящее время. Подпишитесь на список рассылки, если у вас есть вопросы.
теория
6

Если вы предпочитаете, чтобы тестирование хранимых процедур проводилось исключительно на SQL, взгляните на http://tsqlt.org/

Он совместим с MS SQL 2005 SP2 и выше, и его преимущество заключается в том, что разработчикам не нужно знать C # или другой язык для реализации тестов.

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

Ален Кинг
источник