Непрерывная интеграция: обновление схемы тестовой БД
Я создаю сервер непрерывной интеграции (Hudson) для создания проекта Java и запускаю соответствующие тесты unit/integration. Большинство этих тестов обращаются к базе данных, а тестовые данные хранятся в XML файле DbUnit.
Я ищу способ автоматического поддержания схемы тестовой базы данных в актуальном состоянии. В настоящее время SQL script для конкретной версии хранится в каталоге с именем после версии выпуска:
└───scripts
├───0.1.0
├───0.1.1
├───0.1.2
├───0.1.4
Например, SQL script для версии 0.1.4 -
scripts\0.1.4\script-0.1.4.sql
Проблема заключается в том, что эти скрипты содержат смесь изменений схемы (например, ALTER TABLE...) и изменения статических таблиц (например, добавьте новую роль в таблицу USER_TYPE).
В случае модульных тестов я хочу только применить изменения схемы, потому что, как упоминалось выше, все данные для модульных тестов хранятся в XML файле DbUnit. Хотя я мог бы разделить эти два типа изменений базы данных на разные файлы, часто возникает зависимость между изменениями схемы и изменениями данных, которые необходимо будет каким-то образом применять, когда релиз применяется к QA, производству и т.д.
В любом случае, это всего лишь очень длинный способ спросить, есть ли у кого-нибудь надежный способ автоматически обновить свою тестовую схему? Я знаю Unitils имеет некоторую поддержку для поддержания тестовой схемы в актуальном состоянии, но я не уверен, может ли она игнорировать 'операторы обновления данных в сценариях SQL-дельта.
Ответы
Ответ 1
В предыдущем плакате список Liquibase как опция, однако они не указали на способность Liquibase определять правила, которые выполняются в определенных контекстах (Контексты в Liquibase). Это позволяет вам иметь обновления схемы, не помеченные каким-либо конкретным контекстом, и светильники для модульных тестов, помеченные как контекст test
. Таким образом, светильники будут вставлены только после запуска модульных тестов.
Вот пример набора изменений Liquibase, который содержит схему и светильники:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
<changeSet author="avalade" id="1">
<createTable tableName="users">
<column autoIncrement="true" name="id" type="long">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="email" type="varchar(255)" />
</createTable>
</changeSet>
<changeSet author="avalade" id="2" context="test">
<insert tableName="user">
<column name="id" value="1" />
<column name="email" value="[email protected]" />
</insert>
</changeSet>
</databaseChangeLog>
Затем, если вы используете Spring для управления своими DAO, вы можете поместить следующее в свой файл контекста приложения, который вы развертываете:
<bean id="liquibase" class="liquibase.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:dbChangelog.xml" />
</bean>
Для файла контекста приложения, который вы используете в своих модульных тестах, настройте Liquibase с дополнительным свойством контекста:
<bean id="liquibase" class="liquibase.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:dbChangelog.xml" />
<property name="contexts" value="test" />
</bean>
Таким образом, вы можете хранить все определения базы данных вместе в одном месте и только вставлять свои приборы, когда вы запускаете тестовый код.
Ответ 2
То, что мы нашли как наиболее управляемый способ управления постепенной эволюцией живых/тестовых схем БД, использует инструмент управления миграцией схемы, например Liquibase
Это позволяет нам применять последние изменения схемы в любой среде, которую мы так выбираем, тестируем или иным образом, последовательно, что позволяет нам запускать любую автоматизацию, которую мы желаем, против современной схемы.
Ответ 3
Что я делаю в своих тестах:
- Я сохраняю версию DB где-то
- В первом тесте я разрушаю всю БД и строю ее с нуля
- Я запускаю каждое обновление схемы в отдельном тесте
- Я запускаю модуль "Обновление БД" в качестве индивидуального теста (не должен ничего делать, потому что все изменения уже применяются). При желании я снова сбрасываю DB и запускаю его один раз.
- Я загружаю тестовые данные в БД (некоторые из вышеприведенных тестов сделают это, если они исправят ошибки данных).
Теперь тестовая БД готова к "реальным" (прикладным) испытаниям. После каждого из тестов приложения я откатываю текущую транзакцию, поэтому тестовая БД никогда не изменяется после установки.
Чтобы ускорить тестирование, я обычно имею три тестовых набора: один, который содержит в настройке БД, тот, который содержит только те тесты приложений и тот, который содержит два других набора. Это позволяет мне быстро reset тестовую БД и запустить один тест из набора приложений.
Ответ 4
В настоящее время я использую аналогичный подход. Я изучал инструменты миграции db и не нашел того, который решает проблему, которую вы описываете.
Проблема в том, что иногда изменение схемы требует, чтобы данные были изменены, чтобы создавать новые ограничения и т.д. В этом случае, если операторы обновления данных были проигнорированы, миграция завершилась с ошибкой.
Добавил бы sql script в ваш тестовый пакет, который удалит вам все данные в базе данных?
Таким образом, процесс будет следующим:
- выполнить миграцию db.
- запустите script, чтобы удалить все данные в db.
- данные теста нагрузки
- запустить тесты
Ответ 5
Я использую migrateDB для решения этой проблемы.
Этот инструмент основан на понятии, что есть "тесты", которые вы можете выполнить (через SQL) в своей базе данных, чтобы увидеть, было ли применено заданное изменение базы данных, и коррелирующий набор действий для выполнения, если тест "не работает" ". Например, вам может потребоваться запросить схему метаданных, чтобы увидеть, существует ли таблица или столбец, а если нет, создайте ее. Или вы можете посмотреть, существует ли определенная строка в таблице, а если нет, вставьте ее. Он поставляется с несколькими стандартными тестами и действиями, предварительно сконфигурированными, и очень легко добавить свои собственные (только с конфигурацией XML - никакого нового кода для этого).
В качестве небольшого бонуса каждый из этих тестов и действий настроен для каждого "диалекта" SQL (так, например, у вас может быть диалект "оракул" и диалект "mySQL".) Это означает, что как только вы определить запросы для данных тестов и действий для каждого диалекта, каждый новый экземпляр теста или действия не требует нового SQL и может быть выполнен против нескольких целевых баз данных.
Затем вы просто поддерживаете небольшой XML файл, в котором перечислены тесты и соответствующие действия, и запускайте инструмент против вашей базы данных после каждой сборки.
Это хорошо работает для нас.
Ответ 6
Вот что мы делаем:
$ find src/sql/ | grep -v /.svn
src/sql/
src/sql/0000-system.sql
src/sql/0000-system.sql.dev.log
src/sql/0000-system.sql.prod.log
src/sql/0000-system.sql.test.log
src/sql/0001-usgn.sql
src/sql/0001-usgn.sql.dev.log
src/sql/0001-usgn.sql.prod.log
src/sql/0001-usgn.sql.test.log
src/sql/0002-usgn.sql
src/sql/0002-usgn.sql.dev.log
src/sql/0002-usgn.sql.prod.log
src/sql/0002-usgn.sql.test.log
src/sql/0003-usgn.sql
src/sql/0003-usgn.sql.dev.log
src/sql/0003-usgn.sql.prod.log
src/sql/0003-usgn.sql.test.log
src/sql/0004-system.sql
src/sql/0004-system.sql.dev.log
src/sql/0005-usgn.sql
src/sql/purge.sql
у нас есть scriptseq ### - databaseusercredential.sql
Теперь наши тесты всегда позволяют неизвестно начать состояние данных в БД. Если бы вы не могли этого сделать, я бы предложил вам использовать SEQ-CRED-TYPE.sql, где type будет dml/ddl и отфильтровать скрипты dml.