LoginSignup
2
0

More than 1 year has passed since last update.

【Rails】【Rspec】トランザクションのロールバックをテストする

Last updated at Posted at 2022-07-09

はじめに

未経験からエンジニアに転職して、3ヶ月経つエンジニアです。

アイコンバー.JPG

今回は業務で経験した「トランザクションのロールバックをテストする」方法について書きます。

トランザクションとは

ブロック内のすべての処理が正常に行われた場合に保存
エラーが発生した場合は、ロードバック

これだけだとわかりませんよね、、
↓の記事などが参考になるかもしれません!

テストしていく

トランザクションを使っているということは、重要な処理をしている可能性が高いです。
つまり、コードにバグが含まれていると取り返しのつかないことになり得る危険性が高いともいえます。
テストを堅牢にしたくなるのが自然な流れですね。

結論

describe 'transfer' do
  # 必要なデータを用意する
  let!(:user) { create(:user) }
  create(:money, ...)
  ...

  it 'should rollback if raise Error' do
    allow(Money).to receive(:update_statuses!).and_raise(StandardError)
    expect { XXXXX }.not_to change(Money, :count)
  end  
end

トランザクション内の処理をスタブして、例外を吐くようにする。例外を検知したトランザクションはロールバックをする。
 → レコードの数に変化がないか検証する(テストする)

class Money < ApplicationRecord

enum status: [:pending, :completed]

 def transfer
   ... # お金を振り込む処理
 end

def update_statuses!
 ... # 振り込みが完了したらステータスを更新する
end

上記のような、
お金を振り込む
→ 振り込みが完了したらステータスを更新する
というプログラムがあるとします。
下記のような感じでトランザクションで囲っているとします。

ActiveRecord::Base.transaction do
  Money.transfer
  Money.update_statuses!
end

トランザクション内でなんらかの理由でエラーが起きた時に、
ちゃんとロールバックしているかテストしていきます。

describe 'transfer' do
  # 必要なデータを用意する
  let!(:user) { create(:user) }
  create(:money, ...)
  ...

  it 'should rollback if raise Error' do
    allow(Money).to receive(:update_statuses!).and_raise(StandardError)
    expect { XXXXX }.not_to change(Money, :count)
  end  
end

ポイントはスタブするという点です。

allow(Money).to receive(:update_statuses!).and_raise(StandardError)

スタブとは、「防ぐ」「止める」というようなイメージで考えてみてください。
ここではトランザクション内の2つ目の処理でスタブしています。
.and_raise(StandardError) することで、例外を吐くようにしました。
これで、ロールバックが発生するので、あとはレコードが増えていないことを検証すればOKです。

expect { XXXXX }.not_to change(Money, :count)

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0