Unit-Testing: настройка базы данных для тестирования
Я пишу unit-тесты для приложения, которое использует базу данных, и я хотел бы иметь возможность запускать приложение против некоторых образцов/тестовых данных, но я не уверен в наилучшем способе настройки начальные тестовые данные для тестов.
То, что я ищу, - это средство для запуска кода под тестом с той же базой данных (или схематически идентичной), которую я сейчас использую во время отладки - и перед каждым тестом я хотел бы убедиться, что база данных reset до чистого листа перед вставкой тестовых данных.
Я понимаю, что использование шаблона IRepository позволит мне удалить сложность тестирования против реальной базы данных, но я не уверен, что это будет возможно в моем случае.
Любые предложения или статьи, которые могли бы указать мне в правильном направлении?
Спасибо!
- EDIT -
Спасибо всем, это отличные предложения! Я, вероятно, поеду на путь издевательства над уровнем доступа к данным, в сочетании с некоторыми простыми классами настройки, чтобы генерировать именно те данные, которые мне нужны для каждого теста.
Ответы
Ответ 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;
}