Изменение схем базы данных и юнит-тесты - PullRequest
6 голосов
/ 28 августа 2009

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

Чтобы включить модульное тестирование, у меня есть локальная база данных разработчика, которую я очищаю и заполняю известным набором данных в начале каждого теста, используя dbUnit . Все это работает достаточно хорошо, пока таблица, используемая тестом, не изменится, и мне придется вручную обновлять все наборы данных XML. Что является болью. Я полагаю, что другие люди, должно быть, столкнулись с той же проблемой и, надеюсь, нашли хорошее решение этой проблемы. Так что для тестов, которые требуют заполнения базы данных, что вы используете и как вы справляетесь с изменением определений таблиц? (Хотя я использую Java, я открыт для решений, использующих различные технологии.)

EDIT: Чтобы уточнить немного. У меня есть надуманный тест вроде:

void testLoadRevision() {
    database.clear(); // Clears every table dbUnit knows about.
    database.load("load/trevision.xml", "load/tissue.xml");
    SomeDatabaseThingie subject = new SomeDatabaseThingie(databaseProvider);
    Revision actual = subject.load();
    assert(actual, expected);
}

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

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

Приветствия
MLK

Ответы [ 3 ]

3 голосов
/ 11 августа 2010

Ну, как я понимаю, это вопрос объединения того, что уже есть.

Сценарий, описанный выше:

  1. Написать миграцию базы данных
  2. Применение миграции базы данных (вручную или автоматически в начале тестового прогона)
  3. Наблюдайте за перерывом в тестах из-за нарушения ограничения (не ноль)

Вы можете расширить его, чтобы сделать небольшую программу, которая выполняет следующие действия:

  1. Заполните базу данных с помощью DbUnit XML
  2. Применить миграцию базы данных
  3. Извлечение содержимого вашей базы данных на месте в вашем DbUnit XML (и, возможно, также в DTD) (см. Домашняя страница DbUnit -> Часто задаваемые вопросы по DbUnit -> Как извлечь плоский набор данных XML из моей базы данных?)
  4. Проверьте ваш обновленный DbUnit XML (и DTD) в системе контроля версий.

Для применения миграции я искренне рекомендую Flyway . Он поддерживает как Sql (с заменой заполнителей), так и миграции на основе Java. Затем вы можете применить миграции, используя плагин Maven или программно, используя API. Последний идеально подходит для этого случая.

Полный рабочий процесс становится:

  1. Напишите миграцию вашей базы данных
  2. Запустите вашу программу DbUnitXmlDtdUpdater
  3. Наблюдайте, как проходят ваши юнит-тесты

Счастливые дни,

Axel

Отказ от ответственности: я один из разработчиков Flyway.

3 голосов
/ 28 августа 2009

Я думаю, что ответ на этот вопрос состоит из двух этапов:

Существует только одно официальное определение схемы

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

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

При этом инструменты могут не синхронизироваться со схемой, и вам придется вручную обновлять сгенерированные инструментами вещи. Например, я использую Entity Framework для .NET, которая автоматически генерирует классы на основе схемы базы данных. Когда я меняю схему, мне нужно вручную сказать своему инструменту обновить эти классы. Это боль, но я не знаю никакого выхода из этого, если инструмент не поддерживает автоматизацию.

Каждый тест должен начинаться с пустых данных

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

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

Это действительно хорошо объяснено в превосходной книге xUnit Test Patterns .

2 голосов
/ 10 августа 2010

У меня та же проблема с плоскими файлами dbunit xml, которые не синхронизируются при эволюции схемы базы данных, которые требуют изменения данных (даже для таких простых вещей, как добавление обязательных столбцов).

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

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

Если найдена следующая запись в блоге, освещающая проблему: http://blog.liquibase.org/2007/06/unit-testing-the-database-access-layer.html

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

но добавляет себя:

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

... что, в свою очередь, невозможно для более сложных сценариев, я полагаю. Он продолжает говорить:

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

Вот ссылка: www.liquibase.org/manual/contexts, но это, по крайней мере, не то, что я хочу, хотя мне было бы хорошо, если я предоставлю свои тестовые данные инструменту переноса БД, я все еще хотел бы держать его очень тест базы данных.

Кто-нибудь думает?

...