Comments 25
Почему у Вас возникает проблема подключённых пользователей? Можно же просто создавать для тестов совершенно новую базу данных, имя которой никто кроме Вас не знает и соединиться кроме тестового скрипта не может.
Не вижу особой разницы — разворачивать бэкап каждый раз в новую базу или в одну и ту же. Есть ли разница в скорости?
Ещё вопрос — вы предлагаете создавать базу на прогон или на каждый тест?
Ограничить права по подключениям — кажется, здраво. Но как и любая строгость — ведёт к неудобствам. Хочется без заморок подключаться к тестовой базе, используя какой то стандартный логин/пароль и известное имя. Я не обижусь, если меня выкинет, когда я помешаю системе работать.
Ещё вопрос — вы предлагаете создавать базу на прогон или на каждый тест?
Ограничить права по подключениям — кажется, здраво. Но как и любая строгость — ведёт к неудобствам. Хочется без заморок подключаться к тестовой базе, используя какой то стандартный логин/пароль и известное имя. Я не обижусь, если меня выкинет, когда я помешаю системе работать.
У Вас основное, что делает Ваша система подготовки базы — это отключение пользователей. 1) а этим пользователям работать с базой не нужно? и 2) вы запускаете тесты в базе, в которой кто-то уже пошалил и в принципе непонятно годится ли она в качестве эталонной базы. Все проблемы решаются одним — для всего прогона, или для каждого отдельного теста — как будет лучше — создавать новую базу. Можно нового пользователя для подключения к ней — заодно оттестируете и этот аспект, ошибки при смене имени пользователя тоже бывают.
В результате две страницы скриптов превращаются в одну строчку восстановления базы из архива :)
В результате две страницы скриптов превращаются в одну строчку восстановления базы из архива :)
Признаться, было просто просто интересно написать отключающий скрипт и поглядеть как оно работает. Ну а бенефит как раз и получился в том, что базу менять не надо.
В целом, согласен, что решение с созданием базы вяглядит проще.
Не понял тезис про «пошалил» — я ведь перед тестом из бекапа восстанавливаю. Там только если успеть во время теста что то сделать.
В целом, согласен, что решение с созданием базы вяглядит проще.
Не понял тезис про «пошалил» — я ведь перед тестом из бекапа восстанавливаю. Там только если успеть во время теста что то сделать.
Могу вам посоветовать вместо KILL использовать 'ALTER DATABASE SET OFFLINE WITH ROLLBACK IMMEDIATE'
Категорические поддерживю. Приведенный ТС килл-код во-первых громоздок, во-вторых не исключает подключений в процессе тестирования. Но только сделал бы не SET OFFLINE, а SET SINGLE_USER.
Поставил "-" за «Юнит-тесты и БД», если есть база данных то тесты как минимум интеграционные
Не совсем понял, зачем городить такой огород с откатами, когда есть транзакции, поэтому опишу работающую схему в том виде, как это происходит у нас.
Для тестов используется отдельная база, с имеющимся необходимым набором данных, которая лежит на сервере и доступна всем и каждому и на всякий случай каждую ночь восстанавливается из бэкапа.
Если тест изменяет какие-то данные, он оборачивается в транзакцию (TransactionScope в .NET, например), которая после выполнения теста отказывается — таким образом главная задача оставить состояние в том виде, которое было до выполнения теста, решается.
При необходимости добавить в тестовую базу новые данные, они добавляются и делается бэкап, который подменяет тот, который используется для ночного восстановления.
Для тестов используется отдельная база, с имеющимся необходимым набором данных, которая лежит на сервере и доступна всем и каждому и на всякий случай каждую ночь восстанавливается из бэкапа.
Если тест изменяет какие-то данные, он оборачивается в транзакцию (TransactionScope в .NET, например), которая после выполнения теста отказывается — таким образом главная задача оставить состояние в том виде, которое было до выполнения теста, решается.
При необходимости добавить в тестовую базу новые данные, они добавляются и делается бэкап, который подменяет тот, который используется для ночного восстановления.
Ну и конечно юнит-тесты в идеале к БД отношения не имеют, это уже скорее интеграционное тестирование.
Хм, а какое решение, если тестируемый модуль работает с базой данных? Делать какую-то абстракцию и использовать заглушки?
Ну да, абстракция, мок-объекты.
А если за работу с базой отвечает ORM? Много труда будет используемые фишки ORM закрывать через mock-объекты. Хотя это, конечно, правильнее :)
Стандартная и часто описываемая ситуация: есть ORM, есть репозиторий, через ORM тягающий данные. Создаются mock-репозитории, остальное не меняется.
На деле же конечно не всегда все получается так радужно, многие работают сразу напрямую в бизнес-логике через ORM, без всяких прослоек. Так что суровая реальность иногда играет роль, тут вы правы.
На деле же конечно не всегда все получается так радужно, многие работают сразу напрямую в бизнес-логике через ORM, без всяких прослоек. Так что суровая реальность иногда играет роль, тут вы правы.
Для сколь-нибудь серьезного теста использовать транзакцию может быть очень накладно по времени. Я бы даже сказал ооооочень.
Если уж на то пошло, то юнит тесты на то и юнит тесты, что бы тестировать очень небольшой кусок, о каких серьёзных тестах речь?
Кроме того, это не накладнее по времени, чем делать какие-то откаты после каждого теста скриптами. Если же откаты не делать после каждого теста, а делать после выполнения целой тест-сессии, то нарушается весь принцип тестирования — каждый предыдущий тест начинает влиять на следующий.
Кроме того, это не накладнее по времени, чем делать какие-то откаты после каждого теста скриптами. Если же откаты не делать после каждого теста, а делать после выполнения целой тест-сессии, то нарушается весь принцип тестирования — каждый предыдущий тест начинает влиять на следующий.
Давайте себе представим простейший тест, который сравнивает вычисляемое некоторой функцией значение с заданным. За функцией же кроется замысловатый агрегат по некоторым тестовым наборам данных, которые определены на десятках таблиц с миллионами записей. Это «очень небольшой кусок» или как? А если в процессе заполнения этим тестовым набором данных я буду тестировать процедуры заполнения — это будет «нарушение принципа тестирования»?
В общем и целом я просто хотел предупредить, поскольку именно этот способ мы использовали долгое время, что иногда можно столкнуться с ситуацией, когда роллбек после теста идет от нескольких часов, до нескольких дней. И речь идет не о каких-то абстрактных тестах, а конкретных требованиях и наборах данных, полученных от конкретных заказчиков, с конкретным требованием в ТЗ, чтобы во время приемо-сдаточных испытаний получаемые значения соответствовали эталонным.
В общем и целом я просто хотел предупредить, поскольку именно этот способ мы использовали долгое время, что иногда можно столкнуться с ситуацией, когда роллбек после теста идет от нескольких часов, до нескольких дней. И речь идет не о каких-то абстрактных тестах, а конкретных требованиях и наборах данных, полученных от конкретных заказчиков, с конкретным требованием в ТЗ, чтобы во время приемо-сдаточных испытаний получаемые значения соответствовали эталонным.
Абсолютно также делаем. TransactionScope — лучшее и самое красивое решение.
А если у нас в тестах есть свои транзакции, и тесты исследуют подробности их проведения или отката?
Возможны ли какие то сторонние эффекты от такого подхода?
Возможны ли какие то сторонние эффекты от такого подхода?
интересно, можно ли (теоретически, хотя бы) на небольшом базовом наборе нагородить таких транзакций, чтобы они откатывались дольше применения бекапа?
Чисто теоретически — да, практически — нужно очень много данных. Тут дело не в количестве транзакций, а в количестве модифицированных страниц в базе (т.е. операций вставки/удаления/обновления). Чем больше страниц изменено/добавлено -> тем больше записей в журнале транзакций -> тем больше изменений нужно откатывать. А вообще — it depends. Я попробовал сделать это у себя и вот что получилось: я добавил одну строку и затем обновил её же 500000 раз (все это, конечно же, в одной транзакции). Откат этих операций занял примерно 3222 ms. Восстановление базы из бэкапа — 1728 ms.
момент первый — «юнит-тесты работают с базой и меняют её» — это, извините, ни в какие ворота. при тестировании работы с базой уместно говорить об интеграционных тестах.
момент второй — используйте FluentMigrator
момент второй — используйте FluentMigrator
Sign up to leave a comment.
Тесты и БД. Как откатить изменения, сделанные тестом?