この記事は、Ateam LifeDesign Advent Calendar 2022 カレンダー1の13日目の記事です。
CloudEvent関数でRSpecがしたかった
Cloud FunctionsのCloudEvent関数のロジックに手を加える機会があったのですが、本番へデプロイするまで動作確認をする術がありませんでした。
CloudEvent関数への改修は初めてでしたので、普段業務で使用しているRSpecでテストコードを書いて安心してリリースが行えるようDockerでのテスト環境の構築から行いました。
この記事ではCloudEvent関数でのRSpecを使ったテストコードの記述例が当時見られなかったので、備忘録を兼ねて書き残したいと思います。
CloudEvent関数のRSpecの書き方
以下のようなCloudEvent関数を例とする。
内容としてはeventデータが存在したときにFirehoseへデータレコードを配信ストリームに書き込むというもの。
require 'functions_framework'
require 'aws-sdk-firehose'
FunctionsFramework.cloud_event "function" do |event|
any_datas = event.data['any_datas']
firehose_client = Aws::Firehose::Client.new(
access_key_id: 'xxxxx',
secret_access_key: 'xxxxx',
region: 'xxxxx'
)
any_datas.each do |any_data|
next if any_data.nil?
resp = firehose_client.put_record_batch({
delivery_stream_name: 'xxxxx',
records: any_data
})
logger.info("faild count: #{resp.failed_put_count}")
end
end
RSpecでは以下のようにCloudEvent関数をテストすることが出来ます。
require 'rspec'
require 'functions_framework/testing'
describe 'CloudFunction' do
include FunctionsFramework::Testing
let(:event) { FunctionsFramework::Testing.make_cloud_event({ 'any_datas' => ['hoge'] }) }
let(:firehose_client) { double('firehose_client double') }
let(:file_path) { File.join __dir__, '../app.rb' }
let(:resp) { double('resp double') }
before do
allow(Aws::Firehose::Client).to receive(:new).and_return(firehose_client)
allow(firehose_client).to receive(:put_record_batch).and_return(resp)
allow(resp).to receive(:failed_put_count).and_return(0)
end
context 'When data exists' do
it 'function is called' do
FunctionsFramework::Testing.load_temporary file_path do
FunctionsFramework::Testing.call_event('function', event)
expect(firehose_client).to have_received(:put_record_batch).once
end
end
end
end
FunctionsFramework::Testing
が提供するメソッドについて説明します。
FunctionsFramework::Testing.make_cloud_event
FunctionsFramework::Testing.make_cloud_event
でCloudEvent関数に渡すためのcloud eventを作成できます。
FunctionsFramework::Testing.load_temporary
FunctionsFramework::Testing.load_temporary
でテストするCloudEvent関数のパスとブロックを渡します。
FunctionsFramework::Testing.call_event
FunctionsFramework::Testing.call_event
でテストするCloudEvent関数の名前とcloud eventを渡してCloudEvent関数のテストが出来ます。
躓いたところ
最初、FunctionsFramework::Testing.call_event
をsubjectしてCloudEvent関数の結果をテスト出来るだろうと思っていました。
# CloudEvent関数は成功か失敗かが分かるよう実行結果を返すよう修正したうえで
subject { FunctionsFramework::Testing.call_event('function', event) }
it { is_expected.to eq('xxxxxx') }
しかし、FunctionsFramework::Testing.call_event
はCloudEvent関数を呼ぶだけで実行結果を返してくれるものではありませんでした。
これに対してhave_received
マッチャを使用してメソッドが呼ばれることを検証することでCloudEvent関数が期待通りの動作することを確認できるテストコードを書くことが出来ました。
have_received
マッチャは使用したことがなく存在も知らなかったので以下記事を参考にさせていただきました。
まとめ
テストコードがあると不具合を未然に防ぐことが出来るだけでなく、安心して今動いている既存機能に手を加えたり、新たな機能を追加することが出来ます。それでけではなく、リファクタリングを促進できたり、メソッドの結合度を下げたテストコードの書きやすいコードを書きやすくなるなどと多くのメリットがあります。
この記事がCloudEvent関数へのテストの導入に少しでもご参考になれば幸いです。
今回記事を書くにあたって用意したサンプルコードは以下となります。
参考文献