【Rails/RSpec】特定の時だけ共通の処理を実行したい

こんにちは、しきゆらです。
今回は、RSpecで同じ処理を書くことを避ける方法を知ったのでメモしておきます。

 

Railsにてテストを書いているときに、同じようなことを書いてるなぁと思うことがあります。
例えば「このAPIはユーザがいることが前提だ」となると、以下のようなことをいろんなテストで書くことになります。

[ruby]
before do
user = FactoryBot.create(:user)
end
[/ruby]

同じことを書くのは無駄ですよね。
何より繰り返し!修正面倒!!

ということで、このように特定の時に共通する処理を実行してほしい時にどうすればいいかわからなかったので、調べてみた結果をまとめます。

 


RSpec.shared_context

参考:改めて学ぶ RSpec | るびま

これは、共通するテストの内容をまとめて定義できる仕組みです。
例えば、「この時はエラーを返す」のようなときはこれを使えばきれいに共通化できそうです。

 

モジュールを定義

参考:Define helper methods in a module – Helper methods – RSpec Core – RSpec – Relish

もう少し柔軟にやりたければ、moduleを作成してRSpecに追加することもできるようです。
今回はこちらを採用した。

[ruby]
# 行いたい処理を書いたモジュールを作る
module CreateUserModule
def current_user
@user ||= create(:user)
end
end

# RSpecの設定から上記のモジュールを読み込む
RSpec.configure do |config|
config.include UserCreatable
end

# テストでは以下のように書ける
RSpec.describe XXX, type: :request do
current_user #=> Userモデルのモック
end
[/ruby]

さて、これである程度実現できていますが、このままではいつでもcurrent_userが引っ付いてきます。
「ユーザ登録」の処理をテストしたいときなどではこれは不要なはず。
ということで、ユーザがいる前提の時だけ作る方法は以下の通り。

[ruby]
RSpec.configure do |config|
config.include UserCreatable, :create_user # このラベルがついているときだけinclude
end

# テストの頭にラベルを指定してあげる
RSpec.describe XXX, :create_user, type: :request do
current_user #=> Userモデルのモック
end

# ラベルを指定しないと使えない
RSpec.describe YYY, type: :request do
current_user #=> undefined local variable or method `current_user’
end
[/ruby]

これで、必要な時だけcurrent_userメソッドを使えるようになりました。
ユーザがいる前提のテストを書くときは、同じことを繰り返し書かなくてもよくなりました。

使い方次第では、もっといろいろできそうですね。
例えば、独自のタイプを定義することなどができそう。

 

今回はここまで。

おわり