Модульное тестирование кода, использующего базу данных - PullRequest
42 голосов
/ 24 декабря 2008

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

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

OR

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

РЕДАКТИРОВАТЬ: Связанный вопрос, но не дубликат, хотя и весьма важный для рассматриваемого вопроса: Как мне выполнить модульное тестирование на устойчивость?

Ответы [ 11 ]

31 голосов
/ 24 декабря 2008

«Заглушка базы данных», которая стоит внутри, обычно упоминается как «поддельное хранилище» или «фиктивное хранилище». Они хорошая идея. Вы можете кодировать их вручную (несложно для простых случаев) или использовать такую ​​среду, как Rhino Mocks, для их генерации. Ты не упоминаешь, на каком языке ты работаешь. Носороги носорога предназначены для .Net.

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

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

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

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

12 голосов
/ 24 декабря 2008

Если вы используете NHibernate, вы можете очень легко проверить базу данных SQLite в памяти , что очень быстро.

3 голосов
/ 24 декабря 2008

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

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

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

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

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

2 голосов
/ 24 декабря 2008

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

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

2 голосов
/ 24 декабря 2008

Зависит от случая, но на старых системах, где я не хочу заглушать базу данных, я часто представляю интерфейс, скажем, 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, где я устанавливаю ожидания для этих методов.

1 голос
/ 25 декабря 2008

Вот хороший хороший скриншот по этой теме называется Значение малых тестов

1 голос
/ 25 декабря 2008

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

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

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

1 голос
/ 24 декабря 2008

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

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

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

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

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

0 голосов
/ 26 декабря 2008

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

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