我如何testingRails迁移?

我想在运行我写的迁移之后testing某些条件。 目前最好的方法是什么?

为了使这个具体:我做了一个迁移,将一列添加到模型,并给它一个默认值。 但是我忘了更新该模型的所有预先存在的实例,使其具有新列的默认值。 我现有的testing都不会抓住这个,因为它们都是从一个全新的数据库开始,并添加新的数据,这些数据将会有默认值。 但是如果我推动生产,我知道事情会打破,我希望我的testing告诉我。

我发现http://spin.atomicobject.com/2007/02/27/migration-testing-in-rails/ ,但还没有尝试过。 这是非常古老的。 这是最先进的吗?

Peter Marklund具有testing迁移的示例要点: https : //gist.github.com/700194 (在rspec中)。

注意迁移自他的例子改变使用实例方法而不是类方法。

这里有一个总结:

  1. 照常创build迁移
  2. build议: test/unit/import_legacy_devices_migration_test.rbspec/migrations/import_legacy_devices_migration_spec.rb注意:您可能需要显式加载迁移文件,因为rails可能无法为您加载。 这样的事情应该这样做: require File.join(Rails.root, 'db', 'migrate', '20101110154036_import_legacy_devices')
  3. 迁移(就像ruby里的一切),只是一个class级。 testingupdown方法。 如果你的逻辑很复杂,那么我build议把逻辑重构成更小的方法,这样更容易testing。
  4. 在调用up ,先设置一些与迁移前相同的数据,然后声明它的状态就是你期望的状态。

我希望这有帮助。

更新 :自发布以来,我张贴在我的博客示例迁移testing 。

更新 :这是一个testing迁移的想法,即使它们已经在开发中运行了。

编辑 :我已经更新了我的概念validation到一个完整的规范文件使用从我的博客文章人为的例子。

 # 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 

我做了一个向模型添加一列的迁移,并给它一个默认值。 但是我忘了更新该模型的所有预先存在的实例,使其具有新列的默认值。

根据这个陈述,你只是试图testing一个“旧”模型,有默认的,正确的?

理论上你正在testing轨道是否工作。 即,“导轨是否将默认值设置为新添加的列”

在数据库的“旧”logging中添加一列并设置默认值。

因此,您不需要更新其他logging以反映默认设置。 理论上没有什么可以testing的,因为铁轨已经为你testing了。 最后,使用默认值的原因是,您不必更新以前的实例来使用默认值,对吗?

也许看Rails 自己的迁移testing会给你一些提示。

我不知道Rails,但我认为这种方法与我使用以下方法的工具无关:

  • 确保部署版本的数据库脚本在版本控制中进行了适当的标记/标记
  • 基于此,您至less需要三个脚本:从头开始创build旧版本的脚本(1),从头开始创build新版本的脚本(2)以及从旧版本(3)创build新版本的脚本。
  • 创build两个数据库实例/模式。 在一个运行脚本2中,在其他运行脚本1之后是脚本3
  • 比较两个数据库中的结果,对数据字典使用sql查询。

为了testing对实际数据的影响,在执行脚本2和1到3之间将testing数据加载到数据库中。再次运行sql查询,比较结果

您可以考虑使用特定设置对testing套件的独立部分进行运行,以对比生产数据的副本(例如yaml_db )。

这是有点元,如果你知道你的新迁移潜在的问题,你可能会更好,只是提高他们,以满足您的具体需求,但这是可能的。

我只是创build一个类的实例,然后调用或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