【RSpec】before句がdescribeスコープ外にも影響する
//
環境
RSpec 3.8 ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin18] Rails 5.2.2
問題
ひとまずテストする内容だけ列挙して後から中身を実装していこうなんて考えることがあります。そして以下の状況になった時にひとまず走らせてみるかと思うこともあります。
describe HogeController,type: :request do let(:user){create(:user)} # factory_botでユーザ生成 describe "GET #get" do let(:get_page){get hoge_path} before{ login_as(user) } # ログインするヘルパー context "ログインしてアクセス" do it "has status 200" do # レスポンスが帰ってくる get_page expect(response).to eq have_http_status(:ok) end it "別ページへリダイレクトしない" do # ここはまだ実装してない end end end describe "GET #create" do let(:post_create){post hoges_path, params:{~~}} context "ログインしていなかったら" do it "ログインページへリダイレクト" do post_create expect(response).to redirect_to(login_path) # ここでエラー。ログイン状態での処理が成功していることになっている。以前は成功しているテスト。 end end end end
このコントローラでは、アクションの前にログインしていなかったらログインページへリダイレクトする様にbefore_action
にて定義されています。しかし、上のテストを走らせるとcreate
のテストでコケます。get
テストのスコープ内ではbefore
句でログイン処理を定義していますが、これはcreate
のスコープ外なので影響されないはずです。
結論
get
テストのスコープの最後の未実装のテストが悪さをしている様です。
検証
describe HogeController,type: :request do let(:user){create(:user)} # factory_botでユーザ生成 describe "GET #get" do let(:get_page){get hoge_path} before{ login_as(user) } context "ログインしてアクセス" do it "has status 200" do get_page expect(response).to eq have_http_status(:ok) end # 未実装の処理を削除 end end describe "GET #create" do let(:post_create){post hoges_path, params:{~~}} context "ログインしていなかったら" do it "ログインページへリダイレクト" do post_create expect(response).to redirect_to(login_path) end end end end
結果:テスト成功
describe HogeController,type: :request do let(:user){create(:user)} # factory_botでユーザ生成 describe "GET #get" do let(:get_page){get hoge_path} before{ login_as(user) } context "ログインしてアクセス" do it "has status 200" do get_page expect(response).to eq have_http_status(:ok) end it "別ページへリダイレクトしない" do get_page # とりあえず何か書いてみる end end end describe "GET #create" do let(:post_create){post hoges_path, params:{~~}} context "ログインしていなかったら" do it "ログインページへリダイレクト" do post_create expect(response).to redirect_to(login_path) end end end end
結果:テスト成功
以上より、中身が未実装のものがあると、before句の処理内容がロールバックされずに残っていると考えられるかなと。
検証2
describe HogeController,type: :request do let(:user){create(:user)} # factory_botでユーザ生成 describe "GET #get" do let(:get_page){get hoge_path} before{ login_as(user) } context "ログインしてアクセス" do it "has status 200" do get_page expect(response).to eq have_http_status(:ok) end it "別ページへリダイレクトしない" do get_page # とりあえず何か書いてみる end it "未実装のテストがあるよ" do # ここのテストはそのまま end end end describe "GET #create" do let(:post_create){post hoges_path, params:{~~}} it "ここに未実装のテスト" do # ここに未実装のテストをさらに書きます。 end context "ログインしていなかったら" do it "ログインページへリダイレクト" do post_create expect(response).to redirect_to(login_path) end end end end
結果:テスト失敗
describe HogeController,type: :request do let(:user){create(:user)} # factory_botでユーザ生成 describe "GET #get" do let(:get_page){get hoge_path} before{ login_as(user) } context "ログインしてアクセス" do it "has status 200" do get_page expect(response).to eq have_http_status(:ok) end it "別ページへリダイレクトしない" do get_page # とりあえず何か書いてみる end it "未実装のテストがあるよ" do # ここのテストはそのまま end end end describe "GET #create" do let(:post_create){post hoges_path, params:{~~}} it "ここに未実装のテスト" do post_create # とりあえず何か実装してみる end context "ログインしていなかったら" do it "ログインページへリダイレクト" do post_create expect(response).to redirect_to(login_path) end end end end
結果:成功
context
"ログインしていなかったら"句の該当テスト前に、上の二つと同じ様にテストを挟んでみても、同じ結果になりました。it
前で実行されたbefore
句の内容は何か処理がなければ、ロールバックされない様ですね。詳しいことを知っている方がいれば、教えていただけると嬉しいです。