トランザクションのテスト

RailsActiveRecord(DB)のトランザクション処理をテストする際のメモ。

トランザクション処理

簡単な例として以下のコードを考える。

class User
  def destroy_with_transaction
    User.transaction do
      destroy
      raise
    end
  end
end
テストコードを書く

User#destroy_with_transactionは必ず例外が起こるので、トランザクションの働きで、レコードは削除されないことになる。よって、テストコードは以下のようになる。なお、フィクスチャとしてusers.ymlがあるとする。

class UserTest < Test::Unit::TestCase
  self.use_transactional_fixtures = false
  fixtures :users
  
  def setup
    @bob = User.find(1)
  end

  def test_destroy_with_transaction
    @bob.destroy_with_transaction
    assert_not_raise(ActiveRecord::RecordNotFound){User.find(@bob.id)}
  end 
end


トランザクションのテストをする場合には、フィクスチャの機能を制限する必要があるため、use_transactional_fixturesの値をfalseにしておく。
transactionのテスト - yukiwataの日記

この設定を行わないと、テストの実行ごとに自動的にトランザクションが開始・ロールバックされるため、テストコード中のトランザクションが有効にならない(ActiveRecordは現時点ではネストされたトランザクションをサポートしていない)。use_transactional_fixtures をオフにすることで、fixtureの読み込みと消去には insert/delete が使用されるようになり、トランザクションを使用したテストもきちんと機能するようになる。


なお、通常UserTestには、他のテストケースも含まれるだろう。その際に、フィクスチャのトランザクション処理の機能が有効になっていないと、各テストケース内でフィクスチャ(DB)のupdateなどをすると、他のテストケースの時にフィスチャがupdateされた状態になってしまうため、他のテストが落ちる可能性が高い。
よって、トランザクションのテストはtransactions_test.rbのように、トランザクション専用のテストファイルを作成し、その中に記述するようにする。