@koshi_life です。
Rails 標準のテストフレームワーク minitest にて Mock側で例外を発生させるテストケースの書き方の備忘です。
前提
- Rails 5.2.3
- Ruby 2.6.0
- minitest 5.11.3
検証対象モジュール
api_client
をコンストラクタ引数で取り、テスト対象のcoutup
関数は、引数のitem_id
をAPI経由(#get)で取得し、値に1加えてAPI経由(#update)で更新する簡素な内容です。
fuga.rb
class Fuga
def initialize(api_client)
@api_client = api_client
end
def countup(item_id)
error_code = 0
# APIでItem取得
begin
item = @api_client.get(item_id)
rescue StandardError => e
# Case1: テストではココの分岐に入ることを確認します
error_code = 1
return false, error_code
end
# APIでItemの値更新
begin
@api_client.update(item_id, item[:val] + 1)
rescue StandardError => e
# Case2: テストではココの分岐に入ることを確認します
error_code = 2
return false, error_code
end
return true, error_code
end
end
テストコード
api_client
をMock化します。api_client#get
, api_client#update
コール時に例外を捕捉する分岐を通るケースを書いてみます。
Mock#expect-instance_method より
expect(name, retval, args = [], &blk) ⇒ Object
の`&blk`の Procを利用して例外を発生させることができます。
```fuga_test.rb
require 'test_helper'
class FugaTest < ActiveSupport::TestCase
test 'Case1: api_client#getで例外発生' do
item_id = 'id-1'
retval_get = { val: 1 }
args_get = [item_id]
api_mock = MiniTest::Mock.new
api_mock.expect(:get, retval_get) do |args_update|
raise StandardError('Mock#getで例外発生')
end
# 検証したいモジュールを実行します
fuga = Fuga.new(api_mock)
result, error_code = fuga.countup(item_id)
assert_equal(false, result)
assert_equal(1, error_code)
# Mockに送信されたデータを検証します。
api_mock.verify
end
test 'Case2: api_client#updateで例外発生' do
item_id = 'id-2'
retval_get = { val: 2 }
args_get = [item_id]
retval_update = nil
args_update = [item_id, 3]
api_mock = MiniTest::Mock.new
api_mock.expect(:get, retval_get, args_get)
api_mock.expect(:update, retval_update) do |args_update|
raise StandardError('Fuga#updateで例外発生')
end
# 検証したいモジュールを実行します
fuga = Fuga.new(api_mock)
result, error_code = fuga.countup(item_id)
assert_equal(false, result)
assert_equal(2, error_code)
# Mockに送信されたデータを検証します。
api_mock.verify
end
test '参考: 比較用に正常系' do
item_id = 'id-3'
retval_get = { val: 3 }
args_get = [item_id]
retval_update = true
args_update = [item_id, 4]
api_mock = MiniTest::Mock.new
api_mock.expect(:get, retval_get, args_get)
api_mock.expect(:update, retval_update, args_update)
# 検証したいモジュールを実行します
fuga = Fuga.new(api_mock)
result, _ = fuga.countup(item_id)
assert_equal(true, result)
# Mockに送信されたデータを検証します。
api_mock.verify
end
end