Подтвердить что ты не робот

Как проверить миграцию Rails?

Я хочу проверить, что определенные условия сохраняются после выполнения миграции, которую я написал. Какой самый лучший способ сделать это?

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

Я нашел http://spin.atomicobject.com/2007/02/27/migration-testing-in-rails/, но не пробовал. Это очень старый. Это современное состояние?

4b9b3361

Ответ 1

Peter Marklund содержит пример тестирования миграции здесь: https://gist.github.com/700194 (в rspec).

Миграции заметок изменились с момента его использования, чтобы использовать методы экземпляра вместо методов класса.

Здесь резюме:

  • Создание миграции как обычно
  • Создайте файл, чтобы выполнить тест миграции. Предложения: test/unit/import_legacy_devices_migration_test.rb или spec/migrations/import_legacy_devices_migration_spec.rb ПРИМЕЧАНИЕ. Вероятно, вам нужно явно загрузить файл миграции, поскольку рельсы, вероятно, не загрузят его для вас. Что-то вроде этого должно делать: require File.join(Rails.root, 'db', 'migrate', '20101110154036_import_legacy_devices')
  • Миграции (как и все в рубине), просто класс. Проверьте методы up и down. Если ваша логика сложная, я предлагаю реорганизовать биты логики на более мелкие методы, которые будут легче протестировать.
  • Перед вызовом up настройте некоторые данные, как это было до вашей миграции, и утвердите, что это состояние - это то, что вы ожидаете после этого.

Надеюсь, это поможет.

ОБНОВЛЕНИЕ. После публикации этого сообщения я разместил в своем блоге пример теста миграции .

UPDATE. Здесь есть идея тестирования миграции даже после того, как они были запущены в процессе разработки.

EDIT. Я обновил свою концепцию доказательства до полного файла спецификации, используя надуманный пример из моего сообщения в блоге.

# spec/migrations/add_email_at_utc_hour_to_users_spec.rb
require 'spec_helper'

migration_file_name = Dir[Rails.root.join('db/migrate/*_add_email_at_utc_hour_to_users.rb')].first
require migration_file_name


describe AddEmailAtUtcHourToUsers do

  # This is clearly not very safe or pretty code, and there may be a
  # rails api that handles this. I am just going for a proof of concept here.
  def migration_has_been_run?(version)
    table_name = ActiveRecord::Migrator.schema_migrations_table_name
    query = "SELECT version FROM %s WHERE version = '%s'" % [table_name, version]
    ActiveRecord::Base.connection.execute(query).any?
  end

  let(:migration) { AddEmailAtUtcHourToUsers.new }


  before do
    # You could hard-code the migration number, or find it from the filename...
    if migration_has_been_run?('20120425063641')
      # If this migration has already been in our current database, run down first
      migration.down
    end
  end


  describe '#up' do
    before { migration.up; User.reset_column_information }

    it 'adds the email_at_utc_hour column' do
      User.columns_hash.should have_key('email_at_utc_hour')
    end
  end
end

Ответ 2

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

На основе этого утверждения вы просто пытаетесь проверить, что "старая" модель имеет значение по умолчанию, правильно?

Теоретически вы проверяете, работают ли рельсы. I.e., "Рельсы устанавливают значение по умолчанию для вновь добавленного столбца"

Добавление столбца и установка значения по умолчанию будут присутствовать в "старых" записях вашей базы данных.

Итак, вам не нужно обновлять другие записи, чтобы отразить настройку по умолчанию. Теоретически нечего тестировать, поскольку рельсы проверили это для вас. Наконец, причина использования настроек по умолчанию заключается в том, что вам не нужно обновлять предыдущие экземпляры, чтобы использовать это значение по умолчанию, правильно?

Ответ 4

Я не знаю Rails, но я думаю, что подход тот же независимо от инструментария Я использую следующий подход:

  • убедитесь, что развернутые версии сценариев базы данных помечены тегом/помечены в Control Version
  • на основе того, что вам нужно как минимум три сценария: script, который создает старую версию с нуля (1), script, которая создает новую версию с нуля (2) и script, которая создает новая версия из старой версии (3).
  • создать два экземпляра/схемы db. За один проход script 2, в другом прогоне script 1, а затем script 3
  • сравнить результаты в двух базах данных, используя sql-запросы к словарю данных.

Для тестирования также влияние на фактические данные, загрузите тестовые данные в базы данных после выполнения script 2 и между 1 и 3. Снова запустите sql-запросы, сравните результаты

Ответ 5

Вы можете рассмотреть возможность запуска отдельных частей вашего тестового набора с определенными настройками против копий ваших производственных данных (например, что-то вроде yaml_db).

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

Ответ 6

Я просто создаю экземпляр класса, затем нажимаю на него up или down.

Например:

require Rails.root.join(
  'db',
  'migrate',
  '20170516191414_create_identities_ad_accounts_from_ad_account_identity'
)

describe CreateIdentitiesAdAccountsFromAdAccountIdentity do
  subject(:migration) { described_class.new }

  it 'properly creates identities_ad_accounts from ad account identities' do
    create_list :ad_account, 3, identity_id: create(:identity).id

    expect { suppress_output { migration.up } }
      .to change { IdentitiesAdAccount.count }.from(0).to(3)
  end
end