2011-05-21 73 views
47

我想測試運行我編寫的遷移後的特定條件。目前最好的方法是什麼?如何測試Rails遷移?

爲了使這個具體:我做了一個遷移,將一列添加到模型,並給它一個默認值。但是我忘了更新該模型的所有預先存在的實例,以便爲新列創建該默認值。我現有的測試都不會抓住這一點,因爲它們都以新的數據庫開始並添加新數據,這些數據將具有默認值。但是如果我推動生產,我知道事情會崩潰,我希望我的測試告訴我。我發現http://spin.atomicobject.com/2007/02/27/migration-testing-in-rails/,但還沒有嘗試過。這是非常古老的。這是最先進的嗎?

+0

非常好的問題。 +1 – d11wtq 2011-05-21 02:22:51

+0

這看起來像一個有用的帖子:http://blog.carbonfive.com/2011/01/27/start-testing-your-migrations-right-now/ – maahd 2016-02-12 14:57:11

回答

3

我做了一個向模型添加一列的遷移,並給它一個默認值。但是我忘了更新該模型的所有預先存在的實例,以便爲新列創建該默認值。

基於此聲明,您只是試圖測試一個「舊」模型,具有默認值,是否正確?

理論上,您正在測試導軌是否可用。即,「鋼軌是否將默認值設置爲新添加的列」

添加列並設置默認值將出現在數據庫的「舊」記錄中。

因此,您不需要更新其他記錄以反映默認設置。理論上沒有什麼可以測試的,因爲Rails已經爲您測試了這一點。最後,使用默認值的原因是,您不必更新以前的實例來使用該默認值,對吧?

0

我不知道Rails的,但我認爲這種方法是獨立於模具 我用下面的方法相同:

  • 使數據庫腳本的肯定部署版本apropiatly標記/標籤版本控制
  • 根據您至少需要三個腳本:從頭開始創建舊版本的腳本(1),從頭開始創建新版本的腳本(2)以及從舊版本創建新版本的腳本版本(3)。
  • 創建兩個db實例/ schemata。在一個運行腳本2中,在另一個運行腳本1後面跟着腳本3
  • 比較兩個數據庫中的結果,對數據字典使用sql查詢。

爲了測試也執行與1和3之間腳本2再次運行SQL查詢後的實際數據,負荷測試數據到數據庫中的效果,比較結果

15

Peter Marklund具有測試的一個例子要旨這裏的遷移:https://gist.github.com/700194(在rspec中)。

注意遷移自他的示例使用實例方法而不是類方法以來已更改。

這裏有一個總結:

  1. 創建遷移照常
  2. 創建一個文件,把你的遷移測試中建議:test/unit/import_legacy_devices_migration_test.rbspec/migrations/import_legacy_devices_migration_spec.rb 注意:您可能需要顯式地加載遷移文件軌道可能不會爲你加載。像這樣的東西應該做的:require File.join(Rails.root, 'db', 'migrate', '20101110154036_import_legacy_devices')
  3. 遷移是(像紅寶石一切),就是一個類。測試updown方法。如果你的邏輯很複雜,我建議將一些邏輯重構成較小的方法,這樣更容易測試。
  4. 調用up,設置一些一些數據,因爲這將是您的遷移之前,並斷言它的狀態,你的期望之後之前。

我希望這會有所幫助。

UPDATE:自發布此消息以來,我在我的博客上發佈了example migration test

UPDATE:這裏有一個想法,即使在開發中運行它們之後,仍然可以測試遷移。

編輯:我已將我的概念證明更新爲完整的spec文件,使用我博客文章中的人爲示例。

# 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 
+0

這聽起來像一個答案的一部分,但通常情況下,該設置從最新的開發數據庫克隆數據庫結構,在這裏我們需要從早期的狀態開始 - 理想情況下,新遷移從未運行過(而不是已經運行並恢復)。使測試數據庫進入適當狀態的便利方法是什麼? – 2013-03-22 17:47:32

+0

@SteveJorgensen這是一個很好的問題。當我編寫遷移測試時,我通常對它們進行TDD,然後在實際運行遷移後將其刪除。他們不會堅持繼續作爲迴歸測試,因爲正如您所說,一旦您遷移了,測試會反映新的遷移狀態,並且遷移測試將失敗。 非常抱歉,我從來沒有處理過如何設置數據庫。我有一個想法,我會盡快更新我的答案,一旦我有機會鼓搗它。 – 2013-03-23 01:08:34

+0

一些Google搜索引起了我一個有趣的相關文章:http://spin.atomicobject。com/2007/02/27/migration-testing-in-rails/ – 2013-03-23 08:30:36

0

你可以考慮運行測試套件的分離部分與特定的設置,對生產數據的副本(例如像yaml_db)。

這是一個有點元,如果你知道有什麼潛在的問題與你的新遷移你很可能會更好只是增強他們掩蓋您的特定需求,但它是可能的。

2

我只需要創建一個類的實例,然後調用它updown

例如:

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