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

Модульное тестирование кода, использующего базу данных

Мне интересно узнать, какой подход люди предпринимают при разработке автоматизированных модульных тестов, которые используют базу данных

Вы устанавливаете базу данных QA (известную начальную точку) до запуска тестового пакета.

ИЛИ

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

EDIT: Связанный с этим вопрос, но не дубликат, хотя и весьма важный для рассматриваемого вопроса: Как я могу сохранить повторяемость unit-test?

4b9b3361

Ответ 1

"Заглушка базы данных", которая стоит внутри, обычно называется "поддельным репозиторием" или "ложным репозиторием". Это хорошая идея. Вы можете запрограммировать их вручную (не сложно для простых случаев) или использовать фреймворк, например Rhino Mocks, для их создания. Вы не говорите, на каком языке вы работаете. Rhino mocks для .Net.

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

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

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

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

Ответ 3

Мы делаем несколько трюков:

edit: У нас есть отдельные базы данных для каждого пользователя. Наш сервер builds также имеет собственную базу данных. Стоимость дополнительных жестких дисков намного меньше, чем затраты разработчиков, влияющих на другие тесты.

  • Наше приложение может генерировать таблицы и выполнять сами шаги обновления (без отдельных сценариев db). Это помогает нашему клиенту, потому что ему нужно только зайти в WAR файл, и он это сделал. Приложение просматривает базу данных и выполняет любые инструкции DDL, необходимые для запуска остальной части контекста Spring.
  • В нашем тестовом пакете есть код, который выгружает контекст Spring, удаляет базу данных и перезапускает контекст с чистой базой данных. Мы можем опционально отключить это, если нам нравится
  • Все наши базы данных /SQL unittests - это Spring тесты интеграции транзакций. Это означает, что после завершения теста транзакции откатываются назад, а другие unittests снова будут искать чистую базу данных.

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

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

Ответ 4

Зависит от случая, но в устаревших системах, в которых я не хочу заглушить базу данных, я часто представляю интерфейс, скажем, IFooDBManager, который имеет методы, возвращающие объекты ADO.Net, такие как таблицы данных или наборы данных. Конечно, это не должен быть интерфейс, но это может быть виртуальный метод, например. Затем в моих тестах я использую небольшой API с плавным интерфейсом, который я создал давно, я использую его для создания наборов данных и таблиц и заполнения их тестовыми значениями, чтобы я мог вернуть их из своих подделок.

Свободный интерфейс выглядит примерно так:

return DataTableBuilder.Create()
    .DefineColumns("a, b")
    .AddRow().SetValue("a", 1).SetValue("b", 2).DoneWithRow()
    .AddRow().SetValue("a", 10).SetValue("b", 20).DoneWithRow()
.Table

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

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

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

Ответ 5

В действительности вы должны сделать то и другое. Когда вы говорите "заготовку базы данных", это намекает на насмешку в модульных тестах. И когда вы говорите о "Установка базы данных QA (известная начальная точка)", это указывает на интеграционные тесты, в которых вы действительно попали в базу данных. Единичные тесты идут намного раньше в игре, и в них насмехается игра. Mocking намного быстрее, чем на самом деле попадание в базу данных. Поэтому, когда вы запускаете много модульных тестов, издевательство будет экономить много времени. Rhino Mocks - отличная основа, которую я использовал лично. Но есть несколько насмешливых фреймворков, найдите тот, который лучше всего подходит вам.

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

Ответ 6

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

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

http://weblogs.asp.net/stephenwalther/archive/2008/03/22/tdd-introduction-to-rhino-mocks.aspx

Ответ 7

Обычно я использую два подхода.

Код, который зависит от уровня абстракции базы данных, работает с IoC и поэтому легко тестируется с помощью mocks/stubs. У вас есть интерфейс IDataAccess или IRepository, и вы проверяете взаимодействие своего кода с ним.

Код, который фактически работает с базой данных (скажем, класс, реализующий IDataAccess), тестируется сам по себе, обычно выполняет округлые поездки в базу данных (insert-retrieve-update-retrieve-delete). Перед запуском каждого тестового примера база данных будет воссоздана или опущена, чтобы избежать перекрестных помех. Это приводит к испытаниям, требующим нескольких минут для запуска вместо нескольких секунд, но, на мой взгляд, важно проверить фактическую базу данных, которую вы будете использовать в процессе производства. Использование замены, такой как SQLite в памяти, не является хорошим выбором, поскольку она слишком отличается от, например, SQL Server.

Ответ 9

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

Ответ 10

Spring имеет тестовые классы, которые являются транзакционными. Соберите тестовые данные, запустите тесты, откиньте их назад. Как будто вы никогда не были там.

Ответ 11

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