После обновления приложения до версии со схемой базы данных 2 нужно убедиться, что данные пользователя не потеряны и корректно преобразованы. Какой сценарий тестирования докажет работу миграции, а не просто успешный запуск на чистом хранилище?
function launch() {
db = openDatabase('app.db', schemaVersion = 2)
profile = db.read('profile')
render(profile.displayName)
}
Нужно установить старую версию приложения, создать в ней реальные данные, обновить приложение поверх неё без удаления, затем проверить запуск, содержимое данных и версию схемы. Отдельно следует проверить чистую установку, но она не подтверждает миграцию: при ней база создаётся сразу в актуальном формате.
Мобильные приложения хранят пользовательские данные в локальной базе, файлах или защищённом хранилище. При выпуске новой версии структура этих данных может измениться, поэтому появился подход с версионированием схемы и последовательными миграциями.
Исходная проблема — обновление должно сохранить существующие данные, хотя новая версия ожидает другой формат. Простая инициализация новой базы решает задачу только для первого запуска и не покрывает сценарий реального обновления.
На устройстве уже могут находиться профиль, черновики, кэш, настройки и записи офлайн-операций. Если приложение открыть после обновления без миграции или выполнить её частично, возможны потеря данных, ошибка чтения, повреждение записей или повторная авторизация пользователя.
Критичный сценарий — обновление поверх установленной версии. Установка версии 2 после удаления версии 1 проверяет только совместимость нового приложения с пустым хранилищем и может скрыть ошибку преобразования старых данных.
Базовый тестовый сценарий выглядит так:
Минимальная модель миграции может выглядеть так:
Версия должна изменяться вместе с успешной миграцией, обычно внутри транзакции. Если преобразование завершилось ошибкой, транзакция должна откатиться или приложение должно безопасно сообщить о проблеме; нельзя помечать незавершённую миграцию как выполненную.
Нужно проверять не только наличие приложения после обновления, но и обратную совместимость данных с пользовательскими сценариями. Важны также обновления через несколько версий, например 1 → 3 и 1 → 2 → 3, если продукт действительно поддерживает оба пути.
На iOS и Android обычное обновление обычно сохраняет данные приложения, но поведение резервного восстановления, очистки данных, корпоративного управления устройством и удаления приложения нужно учитывать отдельно. Нельзя считать данные после переустановки эквивалентными данным после обновления: например, некоторые виды системного защищённого хранения могут иметь отличные от файловой базы правила жизненного цикла.
Компромисс состоит в выборе стратегии миграций. Последовательные миграции проще проверять и надёжнее для пропуска нескольких версий, но увеличивают код и время запуска. Пересоздание базы проще реализовать, однако оно допустимо только для данных, которые можно безопасно восстановить или потерять.
После выпуска версии 3 часть пользователей стала видеть пустой список заказов. На чистой установке ошибка не воспроизводилась, а команда сначала предложила удалять и создавать базу заново.
Рассматривались варианты:
Выбрали третий вариант. Тестировщики подготовили базы версий 1 и 2 с граничными данными, обновляли их до версии 3, прерывали миграцию и повторяли запуск. После исправления миграция стала либо полностью применяться, либо откатываться, а данные заказов сохранялись.
Вопрос: Что изменится в проверке, если приложение должно поддерживать обновление сразу с версии 1 до версии 4?
Ответ: Нужно проверить цепочку миграций 1 → 2 → 3 → 4 либо явно доказать наличие прямой миграции 1 → 4. Нельзя предполагать, что пользователь обязательно запускал каждую промежуточную версию: магазин приложений может обновить приложение через несколько релизов. Также стоит проверить промежуточное состояние после каждого шага, чтобы ошибка на ранней миграции не маскировалась последующей.
Вопрос: Как проверить устойчивость миграции к принудительному завершению приложения?
Ответ: Следует прерывать процесс на разных этапах транзакции, например закрытием приложения, перезагрузкой устройства или остановкой процесса, а затем снова запускать приложение. Ожидаемый результат — старая целостная схема либо полностью новая схема, но не смешанное состояние. Для этого миграция должна быть атомарной или иметь механизм возобновления с понятным маркером состояния.
Вопрос: Почему проверка только структуры базы недостаточна?
Ответ: Схема может формально соответствовать версии, но данные при преобразовании могут потерять значения, изменить кодировку, нарушить связи или получить неверные значения по умолчанию. Поэтому нужно проверять пользовательские инварианты: идентификаторы сохраняются, количество записей не уменьшается без предусмотренной причины, обязательные поля валидны, а приложение может редактировать и повторно сохранять мигрированные данные. Такая проверка выявляет ошибки преобразования, которые не видны при чтении одной лишь версии схемы.