Unit-Testing: настройка базы данных для тестов - PullRequest
21 голосов
/ 24 апреля 2009

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

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

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

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

Спасибо!

- EDIT -

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

Ответы [ 7 ]

14 голосов
/ 24 апреля 2009

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

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

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

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

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

3 голосов
/ 29 апреля 2009

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

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

1 голос
/ 29 июля 2015

Насмешка - лучший способ для модульного тестирования вашего кода.

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

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

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

1 голос
/ 24 апреля 2009

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

0 голосов
/ 10 ноября 2012

Этот код очищает все данные из всех пользовательских таблиц в 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;
}
0 голосов
/ 24 апреля 2009

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

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

0 голосов
/ 24 апреля 2009

Я не думаю, что есть простой способ закончить это. Вам просто нужно создать эти сценарии установки Pre-Test sql и сценарии Tear-down после тестирования. Затем вам нужно запускать эти сценарии для каждого запуска. Многие люди предлагают SQLLite для настройки модульного теста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...