Подтвердить что ты не робот

Unit-Testing: настройка базы данных для тестирования

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

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

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

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

Спасибо!

- EDIT -

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

4b9b3361

Ответ 1

Вот общий подход, который я пытаюсь использовать. Я рассматриваю тесты примерно на трех или четырех уровнях:: unit-tests, тесты взаимодействия, интеграционные тесты, приемочные тесты.

На уровне unit test он просто код. Любое взаимодействие с базой данных разыгрывается вручную или с использованием одной из популярных фреймворков, поэтому загрузка данных не является проблемой. Они работают быстро, и убедитесь, что объекты работают должным образом. Это позволяет выполнять очень быстрые циклы тестирования записи/записи кода/запуска. Макетные объекты обслуживают данные, необходимые для каждого теста.

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

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

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

Ответ 2

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

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

Ответ 3

Я знаю, что вы используете С#, но в Java World есть среда Spring. Он позволяет запускать мини-проекты базы данных в транзакции, и после этой транзакции вы откатываете это обратно. Это означает, что вы работаете с реальной базой данных, не касаясь состояния после завершения теста. Возможно, это может быть намеком на дальнейшее исследование на С#.

Ответ 4

Mocking является лучшим способом для unit test вашего кода.

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

Я использую локальный экземпляр MySql для тестов интеграции в нескольких проектах. Проблема возврата - это настройка сервера и создание тестовых данных. Я создал небольшой пакет Nuget под названием Mysql.Server(подробнее см. https://github.com/stumpdk/MySql.Server), который просто устанавливает локальный экземпляр MySql каждый раз вы запускаете свои тесты.

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

Ответ 5

Я не думаю, что есть простой способ закончить это. Вам просто нужно создать те сценарии настройки SQL-теста и тестовые сценарии с последующим тестированием. Затем вам нужно запустить эти сценарии для каждого прогона. Многие люди предлагают SQLLite для установки unit test.

Ответ 6

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

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

Ответ 7

Этот код очищает все данные от всех пользовательских таблиц в MS SQL Server:

private DateTime _timeout;

public void ClearDatabase(SqlConnection connection)
{
    _timeout = DateTime.Now + TimeSpan.FromSeconds(30);
    do
    {
        SqlCommand command = connection.CreateCommand();
        command.CommandText = "exec sp_MSforeachtable 'DELETE FROM ?'";
        try
        {
            command.ExecuteNonQuery();
            return;
        }
        catch (SqlException)
        {
        }
    } while (!TimeOut());

    if (TimeOut())
        Assert.Fail("Fail to clear DB");
}

private bool TimeOut()
{
    return DateTime.Now > _timeout;
}