2008-09-28 2 views
263

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

Но тестирование ORM и самой базы данных всегда было чревато проблемами и компромиссами.

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

  • Загрузить тестовую базу данных с известными данными. Выполните тесты против ORM и убедитесь, что вернулись правильные данные. Недостатком здесь является то, что ваша тестовая БД должна не отставать от любых изменений схемы в базе данных приложений и может выйти из синхронизации. Он также полагается на искусственные данные и не может выявлять ошибки, возникающие из-за глупого ввода пользователем. Наконец, если тестовая база данных невелика, она не выявит неэффективности, как недостающий индекс. (ОК, это последнее, на самом деле это не то, для чего нужно использовать модульное тестирование, но это не повредит.)

  • Загрузите копию базы данных производства и протестируйте ее. Проблема здесь в том, что вы, возможно, не знаете, что находится в производственной БД в любой момент времени; ваши тесты, возможно, потребуется переписать, если данные со временем меняются.

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

  • Используйте сервер базы данных mock и проверяйте только, что ORM отправляет правильные запросы в ответ на вызов метода.

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

ответ

116

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

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

  2. Используйте сервер непрерывной интеграции для построения схемы базы данных, загрузки образцов данных и запуска тестов. Вот как мы храним нашу тестовую базу данных в синхронизации (перестраиваем ее при каждом тестовом прогоне). Хотя для этого требуется, чтобы сервер CI имел доступ к собственному выделенному экземпляру базы данных и владел им, я говорю, что наличие нашей схемы db, построенной 3 раза в день, значительно помогло найти ошибки, которые, вероятно, не были бы найдены до момента доставки (если не позже). Я не могу сказать, что я перестраиваю схему перед каждой фиксацией. Кто-нибудь? При таком подходе вам не придется (ну, может быть, нам следует, но это не очень важно, если кто-то забывает).

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

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

  1. копия будет устаревать из производственной версии
  2. будут внесены изменения в схему копии, и не получил бы распространяться на производственные системы , На этом этапе у нас были бы расходящиеся схемы. Не весело.

Mocking Database Server:
Мы также делаем это при моей текущей работе. После каждой фиксации мы выполняем модульные тесты против кода приложения, в который вводится макет db accessors. Затем три раза в день мы выполняем полную конструкцию db, описанную выше. Я определенно рекомендую оба подхода.

+20

Загрузка копии рабочей базы данных также имеет последствия для безопасности и конфиденциальности. Как только он становится большим, его копия и размещение его в вашей среде разработки могут иметь большое значение. – 2009-03-29 23:43:26

+0

Честно говоря, это огромная боль. Я новичок в тестировании, и я также написал орму, который хочу протестировать. Я уже использовал ваш первый метод, но прочитал, что он не делает тестовый блок.Я использую специфические функциональные возможности db, и поэтому насмехаться над DAO будет сложно. Я думаю, что плохо использовал мой текущий метод, так как он работает, а другие его используют. Автоматические тесты rock btw. Благодарю. – frostymarvelous 2011-08-06 14:04:21

11

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

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

Основная проблема, которую я вижу с этим подходом, заключается в том, что вы охватываете только код, который взаимодействует с вашим уровнем DAO, но никогда не тестирует сам DAO, и по моему опыту я вижу, что на этом слое много ошибок также. Я также держу несколько единичных тестов, которые работают против базы данных (ради использования TDD или быстрого тестирования локально), но эти тесты никогда не запускаются на моем сервере непрерывной интеграции, поскольку мы не храним базу данных для этой цели, и я думаю, что тесты, выполняемые на сервере CI, должны быть автономными.

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

Несмотря на то, что этот вопрос не вызывает сомнений, этот подход улучшает ваше покрытие, есть несколько недостатков, поскольку вы должны быть как можно ближе к ANSI SQL, чтобы он работал как с вашей текущей СУБД, так и с встроенной заменой.

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

46

Я всегда работаю тесты против БД в оперативной памяти (HSQLDB или Derby) по следующим причинам:

  • Это заставляет вас думать, какие данные сохранить в тестовой БД и почему. Просто вытаскивание вашей производственной БД в тестовую систему переводится как «Я не знаю, что я делаю, или почему, и если что-то ломается, это не я!» ;)
  • Это гарантирует, что база данных может быть воссоздана с небольшим усилием на новом месте (например, когда нам нужно реплицировать ошибку с производства)
  • Это очень помогает в улучшении качества файлов DDL.

В памяти БД загружаются свежие данные после запуска тестов и после большинства тестов я вызываю ROLLBACK, чтобы сохранить его стабильным. ВСЕГДА сохраняйте данные в тестовой БД стабильными! Если данные постоянно меняются, вы не можете проверить.

Данные загружаются из SQL, базы данных шаблонов или дампа/резервной копии. Я предпочитаю дампы, если они находятся в читаемом формате, потому что я могу поместить их в VCS. Если это не сработает, я использую CSV-файл или XML. Если мне придется загружать огромное количество данных ... я этого не делаю. Вам никогда не придется загружать огромное количество данных :) Не для модульных тестов. Тесты производительности - еще одна проблема, и применяются разные правила.

3

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

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

8

Даже если есть инструменты, которые позволяют издеваться вашу базу данных в той или иной форме (например, jOOQ «s MockConnection, который можно увидеть в this answer - оговорке, я работаю продавцом jOOQ в), я бы посоветовал не для издевательства больших баз данных со сложными запросами.

Даже если вы просто хотите интеграции тестировать свой ORM, нужно учитывать, что ОРМ выдает очень сложную серию запросов к базе данных, которые могут изменяться в

  • синтаксиса
  • сложность
  • заказа (!)

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

0

Для проекта на основе JDBC (прямо или косвенно, например JPA, EJB, ...) вы можете макетировать не всю базу данных (в таком случае было бы лучше использовать тестовый db на реальной РСУБД), но только макет на уровне JDBC.

Преимущество - это абстракция, которая поступает таким образом, поскольку данные JDBC (набор результатов, количество обновлений, предупреждение, ...) являются такими же, как и бэкэнд: ваш prod db, test db или только некоторые макеты данных для каждого теста.

С подключением JDBC для каждого случая нет необходимости управлять тестовым db (очистка, только один тест во время, перезагрузка светильников, ...). Каждое соединение макета изолировано и нет необходимости очищать. В каждом тестовом случае предусмотрены только минимальные необходимые светильники для моделирования JDBC-обмена, которые помогают избежать сложности управления целым тестовым db.

Основы Acolyte включают драйвер JDBC и утилиту для такого макета: http://acolyte.eu.org.

Смежные вопросы