【RSpec】モックを使ったテスト
こんにちは!メグミです!
今回は モックを使ったテストの書き方について書きたいと思います!
はじめに
処理の中でジョブを呼んだりする場合があると思いますが、
実際のジョブのテストは別で作成しているので、ジョブが呼ばれたかのテストをしたい!
ということがありました。テストの書き方について理解が曖昧だったので調べてみました!
基本的な書き方
Article
モデルにtitle
メソッドがある場合
allow(article).to receive(:title).and_return("タイトル")
allow(実装を置き換えたいオブジェクト).to receive(置き換えたいメソッド名).and_return(返却したい値やオブジェクト)
メソッドの引数が1つ以上ある場合
allow(article).to receive(:title).with(argument_1, argument_2).and_return("タイトル")
やりたいこと
ある処理の中でジョブが任意の引数を受け取って呼ばれているかテストしたい
以下のようなメール送信処理のジョブがあるとします。
class UserMailJob < ApplicationJob
def perform(recipients, subject, body)
# メール送信処理
end
end
以下のクラスのsend_email
メソッドで宛先が入力されていればメール送信処理を非同期で実行します。
宛先が未入力であればジョブは呼ばれません。
class SomeClass
def send_email(recipients, subject, body)
if recipients.present?
UserMailJob.perform_later(recipients, subject, body)
{ is_success: true, message: "送信処理を開始しました。") }
else
{ is_success: false, message: "送信に失敗しました。") }
end
end
end
このような処理のテストを書く場合、
ジョブの処理についてのテストは別途書くべきなので、
このジョブが非同期で呼ばれているかのテストを書く必要があります。
let!(:recipients) { ["megumi@example.com", "helen@example.com"] }
let!(:subject) { "メールの件名です。" }
let!(:body) { "メールの本文です。" }
subject{ SomeClass.new.send_email(recipients, subject, body) }
before do
# UserMailJob クラスの perform_later が任意の引数で呼ばれると true を返すようモック化
allow(UserMailJob).to receive(:perform_later).with(recipients, subject, body).and_return(true)
end
context "宛先が入力されている場合" do
it "メール送信処理が1回呼ばれること" do
subject
expect(UserMailJob).to have_received(:perform_later).with(recipients, title, body).once
end
end
context "宛先が未入力の場合" do
let!(:recipients) { nil }
it "メール送信処理が呼ばれないこと" do
subject
expect(UserMailJob).not_to have_received(:perform_later).with(recipients, title, body)
end
end
UserMailJob
クラスをモック化し、
非同期であるperform_later
の処理が呼ばれることをテストできるようになりました!
また、with
を使って引数を検証することで呼ばれないこともテストしています。
さいごに
他にもいろんなメソッドがあるので気になる方は調べてみてください!
- https://github.com/rspec/rspec-mocks
- https://relishapp.com/rspec/rspec-mocks/v/3-9/docs/setting-constraints/matching-arguments
以上、RSpecでのモックを使ったテストの書き方でした!
おわり