Стратегия для запуска тестов в базе данных - PullRequest
7 голосов
/ 20 апреля 2011

Я начал работать над существующим проектом с более чем 1800 функциональными / интеграционными тестами. Они были закодированы с помощью MSTest.

Многие из них подключаются напрямую к базе данных SQL Server. База данных генерируется генератором кода, который, помимо прочего, создает базу данных. Генерация БД медленная и громоздкая.

Это как следующие проблемы:

  • Тест очищает базу данных, что означает, что мы должны поддерживать отдельную базу данных для тестов и другую для использования приложения. Процедура прямо сейчас заключается в изменении базы данных при переключении между запуском теста и запуском приложения.
  • Каждая ветвь должна иметь свой собственный дБ, поскольку модель дБ может быть разной в каждом дБ (что означает 2 дБ на ветвь с шагом 1)
  • Это медленно
  • Для запуска теста должна присутствовать установка SQL Server и базы данных

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

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

Сначала я изменил наш базовый тестовый класс для подключения к базе данных SQLite, которая была бы создана генератором кода, который уже генерирует основную базу данных вместо базы данных SQL Server. SQLite может быть удален и повторно скопирован в тестовую папку между каждым запуском. Это было бы быстро, не требовало иметь 2 базы данных SQL Server, фактически, если бы только выполнялись тесты, установка SQL Server не потребовалась бы.

Мои проблемы заключались в том, что сгенерированный код использует много концепций, не включенных в SQLite; T-SQL, специфичный для SQL Server синтаксис, схемы, хранимые процедуры и встроенные сборки clr.

Затем я попробовал SQL Server CE 4, который имел многие из тех же ограничений, что и SQLite.

Существуют ли другие альтернативы, кроме переписывания кода для совместимости с SQLite (или CE), переписывания существующих тестов или системы, в которой мы поддерживаем 2 seperatedb?

РЕДАКТИРОВАТЬ: Изменен модульный тест на функциональные тесты, прояснил некоторые вещи. Положите некоторые вещи жирным шрифтом. Я согласен, что эти тесты не являются правильными юнит-тестами. Я согласен, что насмешка была бы хороша здесь. То, что я пытаюсь сделать, это попытаться исправить беспорядок, с которым я столкнулся.

Ответы [ 6 ]

7 голосов
/ 21 апреля 2011

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

 CREATE DATABASE myDb_snapshot ON
    ( NAME = myDb_snapshot, FILENAME = 'C:\MSSQL\Data\myDb_snapshot.ss' )
 AS SNAPSHOT OF myDb;

Чтобы восстановить после выполнения теста:

 RESTORE DATABASE myDb FROM DATABASE_SNAPSHOT = myDb_snapshot

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

В качестве дополнительного примечания: Запуск модульных тестов на уровне проверенных данных не заменяет выполнение ваших тестов на "реальном"база данных".Многие эффекты "зацепки" не видны снаружи вашей базы данных.(триггеры / значения по умолчанию / разрешения / доступность ресурса).Для более быстрых тестовых случаев и для создания более подключаемого кода, пожалуйста, смоделируйте свой уровень данных.Но в конечном итоге вам придется запускать тестовые наборы на «реальной» базе данных.

7 голосов
/ 20 апреля 2011

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

Я не разработчик .NET, поэтому я не могу рекомендовать лучший Mocking framework / tool, но, возможно, этот вопрос укажет вам направильное направление .

Почему модульные тесты не должны обращаться к ресурсам:

Вы захотите взглянуть на эту проблему по-другому.У вас нет никакого желания тестировать саму базу данных, потому что вы должны предположить, что продукт базы данных, который вы используете, работает правильно.Следовательно, нет необходимости проверять, что $ dao-> save () фактически вставляет запись.Вероятно, вас интересует, вызывается ли метод save () при выполнении какого-либо другого действия, или ваш DAO генерирует правильный оператор INSERT.

Если вы ДОЛЖНЫ делать вызовы из базы данныхв вашем модульном тесте, потому что вы НЕ МОЖЕТЕ высмеивать объекты, выполняющие вызовы из базы данных, вам необходимо провести рефакторинг.

Soap Box Time:

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

3 голосов
/ 20 апреля 2011

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

Оберните каждый тест в System.Transactions.TransactionScope , который автоматически откатится, когда вы закончите. (Если вы хотите, чтобы не откатывался, вы должны присвоить TransactionScope переменной и затем вызвать для нее Complete ().)

public void MyTestMethod()
{
    using (new TransactionScope())
    {
        // do your database tests here
        // rolls back when you're done
    }
}

Пока я не проверял, я прочитал , что вы можете сделать то же самое с System.EnterpriseServices.TransactionAttribute :

[Transaction(TransactionOption.RequiresNew)]
public void MyTestMethod()
{
    // do your database tests here
    // rolls back when you're done (or so I hear)
}
1 голос
/ 20 апреля 2011

Один из основных принципов модульного тестирования заключается в том, что вам не следует полагаться на внешние вещи (файловые системы, базы данных и т. Д.). Одна из распространенных стратегий решения этих проблем - использование фиктивных объектов (я использую EasyMock для Java). Если вы хорошо спроектируете свой код (то есть создадите надежный уровень доступа к данным), вы можете смоделировать объекты, отвечающие за подключение к базе данных, и протестировать код, который зависит от доступа к данным независимо от базы данных.

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

РЕДАКТИРОВАТЬ - Иногда все, что вы можете сделать, это начать с собственного кода, кода с учетом TDD и задним числом добавить тесты ко всему коду, к которому вы прикасаетесь. Со временем вы начнете делать вмятину в этих 1800 тестах. Также в зависимости от того, какую среду тестирования вы используете, вы можете рассмотреть возможность запуска двух пакетов тестов (NEW и OLD), чтобы вы могли запускать свои гладкие современные тесты без необходимости запускать старые

0 голосов
/ 18 апреля 2016

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

CREATE DATABASE [myDb_snapshot] ON
    ( NAME = [myDb], FILENAME = 'C:\MSSQL\Data\myDb_snapshot.ss' )
AS SNAPSHOT OF [myDb];
0 голосов
/ 20 апреля 2011

Генерация БД не должна быть такой медленной и громоздкой. Можете ли вы изменить конфигурацию для запуска с локальной базой данных? Установка SQL Server на компьютере каждого разработчика не очень сложна, и тестирование будет быстрее, поскольку вы уменьшите сетевые задержки.

...