Pull to refresh

Comments 25

Почему у Вас возникает проблема подключённых пользователей? Можно же просто создавать для тестов совершенно новую базу данных, имя которой никто кроме Вас не знает и соединиться кроме тестового скрипта не может.
Не вижу особой разницы — разворачивать бэкап каждый раз в новую базу или в одну и ту же. Есть ли разница в скорости?
Ещё вопрос — вы предлагаете создавать базу на прогон или на каждый тест?
Ограничить права по подключениям — кажется, здраво. Но как и любая строгость — ведёт к неудобствам. Хочется без заморок подключаться к тестовой базе, используя какой то стандартный логин/пароль и известное имя. Я не обижусь, если меня выкинет, когда я помешаю системе работать.
У Вас основное, что делает Ваша система подготовки базы — это отключение пользователей. 1) а этим пользователям работать с базой не нужно? и 2) вы запускаете тесты в базе, в которой кто-то уже пошалил и в принципе непонятно годится ли она в качестве эталонной базы. Все проблемы решаются одним — для всего прогона, или для каждого отдельного теста — как будет лучше — создавать новую базу. Можно нового пользователя для подключения к ней — заодно оттестируете и этот аспект, ошибки при смене имени пользователя тоже бывают.

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

Не понял тезис про «пошалил» — я ведь перед тестом из бекапа восстанавливаю. Там только если успеть во время теста что то сделать.
Могу вам посоветовать вместо KILL использовать 'ALTER DATABASE SET OFFLINE WITH ROLLBACK IMMEDIATE'
Категорические поддерживю. Приведенный ТС килл-код во-первых громоздок, во-вторых не исключает подключений в процессе тестирования. Но только сделал бы не SET OFFLINE, а SET SINGLE_USER.
категорически спасибо за совет, опробую. Посмотрю на поведение при подключенных многих юзерах. Managmet studio у меня не могла перевести базу в автономный режим, когда к ней висели левые подключения ещё — и я не стал копать в этом направлении.
Поставил "-" за «Юнит-тесты и БД», если есть база данных то тесты как минимум интеграционные
Если у меня в базе есть хранимая функция [Core].[String_Split] и хранимка, ее тестирующая — [Test].[Core.String_Split], то вызов последней — интеграционный тест?
Не совсем понял, зачем городить такой огород с откатами, когда есть транзакции, поэтому опишу работающую схему в том виде, как это происходит у нас.

Для тестов используется отдельная база, с имеющимся необходимым набором данных, которая лежит на сервере и доступна всем и каждому и на всякий случай каждую ночь восстанавливается из бэкапа.
Если тест изменяет какие-то данные, он оборачивается в транзакцию (TransactionScope в .NET, например), которая после выполнения теста отказывается — таким образом главная задача оставить состояние в том виде, которое было до выполнения теста, решается.
При необходимости добавить в тестовую базу новые данные, они добавляются и делается бэкап, который подменяет тот, который используется для ночного восстановления.
Ну и конечно юнит-тесты в идеале к БД отношения не имеют, это уже скорее интеграционное тестирование.
Хм, а какое решение, если тестируемый модуль работает с базой данных? Делать какую-то абстракцию и использовать заглушки?
А если за работу с базой отвечает ORM? Много труда будет используемые фишки ORM закрывать через mock-объекты. Хотя это, конечно, правильнее :)
Стандартная и часто описываемая ситуация: есть ORM, есть репозиторий, через ORM тягающий данные. Создаются mock-репозитории, остальное не меняется.
На деле же конечно не всегда все получается так радужно, многие работают сразу напрямую в бизнес-логике через ORM, без всяких прослоек. Так что суровая реальность иногда играет роль, тут вы правы.
Для сколь-нибудь серьезного теста использовать транзакцию может быть очень накладно по времени. Я бы даже сказал ооооочень.
Если уж на то пошло, то юнит тесты на то и юнит тесты, что бы тестировать очень небольшой кусок, о каких серьёзных тестах речь?
Кроме того, это не накладнее по времени, чем делать какие-то откаты после каждого теста скриптами. Если же откаты не делать после каждого теста, а делать после выполнения целой тест-сессии, то нарушается весь принцип тестирования — каждый предыдущий тест начинает влиять на следующий.
Давайте себе представим простейший тест, который сравнивает вычисляемое некоторой функцией значение с заданным. За функцией же кроется замысловатый агрегат по некоторым тестовым наборам данных, которые определены на десятках таблиц с миллионами записей. Это «очень небольшой кусок» или как? А если в процессе заполнения этим тестовым набором данных я буду тестировать процедуры заполнения — это будет «нарушение принципа тестирования»?

В общем и целом я просто хотел предупредить, поскольку именно этот способ мы использовали долгое время, что иногда можно столкнуться с ситуацией, когда роллбек после теста идет от нескольких часов, до нескольких дней. И речь идет не о каких-то абстрактных тестах, а конкретных требованиях и наборах данных, полученных от конкретных заказчиков, с конкретным требованием в ТЗ, чтобы во время приемо-сдаточных испытаний получаемые значения соответствовали эталонным.
Надо сокращать наборы данных на которых фактически выполняются тесты, например вводом фиктивных параметров в хранимки и WHILE (@a is null or @a=tbl.field)
Абсолютно также делаем. TransactionScope — лучшее и самое красивое решение.
А если у нас в тестах есть свои транзакции, и тесты исследуют подробности их проведения или отката?
Возможны ли какие то сторонние эффекты от такого подхода?
договоренность по использованию (точнее не использованию) транзакций в хранимках. По крайней мере для тестируемых
интересно, можно ли (теоретически, хотя бы) на небольшом базовом наборе нагородить таких транзакций, чтобы они откатывались дольше применения бекапа?
Чисто теоретически — да, практически — нужно очень много данных. Тут дело не в количестве транзакций, а в количестве модифицированных страниц в базе (т.е. операций вставки/удаления/обновления). Чем больше страниц изменено/добавлено -> тем больше записей в журнале транзакций -> тем больше изменений нужно откатывать. А вообще — it depends. Я попробовал сделать это у себя и вот что получилось: я добавил одну строку и затем обновил её же 500000 раз (все это, конечно же, в одной транзакции). Откат этих операций занял примерно 3222 ms. Восстановление базы из бэкапа — 1728 ms.
момент первый — «юнит-тесты работают с базой и меняют её» — это, извините, ни в какие ворота. при тестировании работы с базой уместно говорить об интеграционных тестах.
момент второй — используйте FluentMigrator
Sign up to leave a comment.

Articles