Ответ 1
Я согласен с системным архитектором, в наши дни слишком много бизнес-логики вносит свой вклад в базы данных.
В модуле тестирования вашего SQL есть статья о www.sqlservercentral.com.
Guy TDD во мне сказал хорошо, мы можем протестировать материал базы данных.
Системный архитектор во мне сказал, какую логику мы тестируем? В базе данных не должно быть никакой логики, единственной вещью, которую вы должны делать в базе данных, является выбор, обновление или вставка.
Итак, если вы чувствуете потребность в unit test вашем SQL, вы просто очень тщательны, чрезмерно прагматичны или это признак дизайнерского запаха?
Я согласен с системным архитектором, в наши дни слишком много бизнес-логики вносит свой вклад в базы данных.
В большинстве жилых проектов база данных находится в некотором количестве потоков между этапом проекта. Таблицы и столбцы создаются, удаляются или изменяются. Обновлены таблицы поиска. И вы можете тестировать несколько экземпляров базы данных, поэтому полезно иметь некоторую проверку состояния метаданных и данных в базе данных, как часть вашего тестирования регрессии.
Есть несколько случаев, когда я предлагаю тестировать базу данных:
Таблицы и представления: проверьте таблицы и представления, которые вы ожидаете. Убедитесь, что эти таблицы и представления содержат столбцы, которые вы ожидаете. Вы также можете проверить, что таблицы, представления или столбцы, которые вы сбросили в этой вехе, фактически отсутствуют.
Ограничения. Попробуйте выполнить изменения данных, которые должны быть отклонены. Ограничения должны предотвращать эти изменения. Вы можете избежать более поздних ошибок, если обнаружите случаи, когда ограничения не работают.
Триггеры: такие же, как и для ограничений, а также триггеры могут использоваться для каскадных эффектов или для преобразования значений и т.д. Проверьте эти логические пути.
Хранимые процедуры: я поддерживаю осторожность в том, чтобы слишком много логики вводить в базу данных, когда логику легче разрабатывать, отлаживать и поддерживать на прикладном уровне. Но бывают случаи, когда есть веские причины использовать хранимые procs. Часто вы видите, как узкое место производительности решалось путем ввода сложной логики в базу данных. Таким образом, хранимые процедуры не уходят полностью, и тестирование их - хорошая идея.
Данные начальной загрузки: таблицы поиска - это пример данных, которые должны присутствовать даже в "пустой" базе данных. Могут быть и другие примеры. Проверьте, что база данных содержит требуемые данные.
Запросы: код приложения снабжен SQL-запросами. Протестируйте их для обеспечения надлежащей функциональности, а также для повышения производительности. Особенно производительность - потому что один и тот же запрос может хорошо зарекомендовать себя и стать узким местом на следующий день, поскольку объем данных изменяется, индексы растут несбалансированными и т.д.
ORM-классы. Подобно триггерам, классы ORM в вашем приложении могут содержать логику для проверки, преобразования или мониторинга операций с базой данных. Они должны быть протестированы.
Эти тесты не могут быть точно названы "модульным тестированием". Единичное тестирование - это особый тип тестирования, в котором каждый тест не зависит от других тестов, и вы пытаетесь изолировать отдельные единицы кода. Я бы сказал, тестируя базу данных, описанные выше способы являются примером тестирования функциональности.
В вашем SQL содержится логика. Например, булевское условие проверяется в предложении WHERE. Можете ли вы придумать какие-либо способы, с помощью которых SQL может быть неправильным? Если это так, было бы целесообразно протестировать SQL, чтобы убедиться, что эти ошибки отсутствуют?
(Например, какой-то глупый программист, как и я, может случайно ввести "WHILE" вместо "WHERE" в моем комментарии выше!... как и я. Но позже я исправил его. Итак, где мои тесты стекирования??? -)
Различия между модульными тестами/specs и интеграционными тестами/specs.
Если у ваших классов есть и то, то вы нарушаете принцип звука: Разделение проблем.
Ваши тесты должны быть четко определены между модульными тестами для тестирования постоянных неосведомленных блоков POCO/POJO, таких как объекты, службы и интеграционные тесты. Которые предназначены для тестирования, когда ваше приложение попадает в металл.
Тестирование интеграции должно проверять постоянство, такое как репозитории и реализация единичной работы для вашего механизма сохранения (RBDMS), Active Directory, Exchange, файловой системы и электронной почты и т.д.
Если ваш случай использования требует тщательного тестирования точки интеграции, в которой используется триггер, тогда проверьте поведение, а не триггер явно. В будущем вы можете не использовать триггер и вместо этого использовать ORM или AoP-перехватчик.
Эта проблема обсуждается. Если вы спросите администратора базы данных, они подумают, что это лучшая вещь в мире, чтобы все ваши приложения использовали предопределенные хранимые процедуры. Эти дни, хотя и заканчиваются, с Hibernate и LINQ набирают популярность, вы действительно можете использовать базу данных в качестве хранилища информации, и ваш уровень доступа к данным обрабатывает все запросы. Я думаю, что LINQ может сделать все для вас в MS SQL, кроме полнотекстового поиска. Что касается разницы в производительности между SPROC и LINQ, это небрежно. Мое голосование не является кодом в базе данных, всем кодом на уровне доступа к данным yoru и имеет для этого тестирование.
Это зависит от вашей архитектуры базы данных. Если у вас есть только таблицы и представления, я думаю, что модульные тесты не требуются, потому что каждый (или большинство) ошибок будет обнаружен при модульном тестировании в приложении.
Но если у вас есть сложные функции, хранимые процедуры, триггеры и т.д., тогда у вас есть много мест, где может быть ошибка, а приложение unit test не распространяется на них.
Правильный системный архитектор. Не нужно вставлять бизнес-логику в вашу базу данных, и, следовательно, вы на самом деле ничего не тестируете.
Я думаю, это немного перебор. Я полагаю, вы могли бы сделать это и поместить тесты в специальную категорию, чтобы они не работали на каждой сборке, может быть, просто при проверке и запуске на сервере. Обычно при всех модульных тестах вы не нуждаетесь в внешних зависимостях.
Я не делаю TDD непосредственно в моей базе данных, но есть много возможностей, где действительно можно поставить "логику" в базу данных. Ограничения, значения по умолчанию (да, я тоже знаю это ограничение), триггеры и т.д. Часто это лучший способ реализовать некоторую бизнес-логику и обеспечить согласованность базы данных. Большую часть времени я могу убедить себя в правильности с некоторым ручным тестированием и оставить его на этом, но я мог видеть, где кто-то может захотеть сделать TDD с этим.
ИЗМЕНИТЬ
Например, я буду использовать значение по умолчанию для вставки и триггер обновления, чтобы установить поля "последнее обновленное время" в insert/update. В LINQ я поставлю столбец как значение, генерируемое автогенерированием, и сделаю его доступным только для чтения. Для меня это проще, чем добавление обработчика события PropertyChanged, чтобы убедиться, что всякий раз, когда изменяется поле на сущности, изменяется последнее обновленное время. Я проверяю его? Конечно, но вручную и после факта, хотя я сильно предпочитаю TDD для большинства вещей.
Я не знаю, почему, когда мы попадаем на слой db, вся хорошая практика должна идти в окно. Если в этом слое есть логика, это вдвойне важно. Существует отличный инструмент, построенный поверх Fitnesse под названием dbfit, который, как представляется, снимает всю боль с модульного тестирования dblayer. Если вам интересно, вы должны взглянуть.
Пока предложение WHERE не пустое, оно должно быть протестировано.
Здесь мы используем API-интерфейс NHibernate для запроса базы данных. Тем не менее, мы ставим простые модульные тесты для защиты уровня доступа к данным. Рассмотрим это:
public IList<Book> GetBorrowedBooks(User user);
Это может показаться глупым в первую очередь. Но для такой простой ситуации мы имеем дело с как минимум тремя объектами модели: книгой, пользователем, заимствованием и, возможно, возвратом. Любая попытка изменить любой из 3 (или более) классов может нарушить код.
Какова стоимость? Наверное, для написания тестов в этом примере требуется менее 20 минут. С помощью категории в NUnit тесты модуля доступа к данным могут быть настроены для работы ночью, а другие тесты - для каждой фиксации. Медленные тесты модулей доступа к данным не навредят, и они являются спасателями жизни.
DbFit - хороший инструмент для модульного тестирования базы данных. Я считаю целесообразным использовать TDD с SQL, потому что, в конце концов, это декларативный язык с условным ветвлением, агрегатными функциями и т.д. Без тестов на месте, как вы можете быть уверены, что получаете ожидаемый результат?