Rails5からrequest spec推奨になってたのと同時に?、assignsやassert_templateが非推奨になっています。
rails-controller-testingを使う事で、使えてしまうのですが、いずれ使えなくなる可能性があるし、そもそも古い書き方を続けていても未来はないので、使わない形に書き換えてみます。

なぜ非推奨になったかは、こちらのサイトが詳しいので割愛します。
Rails5でコントローラのテストをController specからRequest specに移行する

rails-controller-testing削除

Gemfileの下記を削除

  gem 'rails-controller-testing'
$ rspec
Failures:

  1) Top GET #index 未ログイン behaves like ベースドメイン use index template
     Failure/Error: expect(response).to render_template('index')
     
     NoMethodError:
       assert_template has been extracted to a gem. To continue using it,
               add `gem 'rails-controller-testing'` to your Gemfile.
     Shared Example Group: "ベースドメイン" called from ./spec/requests/top_spec.rb:34
     # ./spec/requests/top_spec.rb:22:in `block (4 levels) in '

render_template(=assert_templateかな?)が使えなくなるという事か。

  2) Top GET #index 未ログイン behaves like ベースドメイン 新しいスペースが10件取得できる
     Failure/Error: expect(assigns(:new_spaces)).to match_array new_spaces
     
     NoMethodError:
       assigns has been extracted to a gem. To continue using it,
               add `gem 'rails-controller-testing'` to your Gemfile.
     Shared Example Group: "ベースドメイン" called from ./spec/requests/top_spec.rb:34
     # ./spec/requests/top_spec.rb:29:in `block (4 levels) in '

assignsが使えないの想定通りだが。

render_template消して良いのか?

悩んだのが、request specとview specの住み分け。
controller specの時は、renderするtemplateが正しい事と、viewに渡す値が正しい事を担保できればOKで、template内はview specで担保と、役割分担が出来ていると理解していた。

そもそもrequest specではrequestをテストする。
結果のHTMLやJSONが返るので、controllerで作られた値がtemplateに埋め込まれて返却される。
controller specでrender_viewsした時と同じ挙動だ。

つまり、request specでtemplate内にcontrollerで渡した値があるかを担保すべきなんだと理解。
じゃあ、view specの役割って何だろう?
templateはデザイナーさんに作って貰ったのを適用する事が多い。
ゆえにHTMLタグを含めたテストは失敗して、直す必要が出て来るので避けている。
この辺は人間なり、Seleniumなりで担保したいので、今までview specに書いたテストをrequest specに移せば良さそう。

書き換え

spec/views/top/index.html.erb_spec.rb はdoとendの中をバッサリ削除。

require 'rails_helper'

RSpec.describe 'top/index', type: :view do
  let!(:user) { FactoryBot.create(:user) }
  shared_context 'login' do
    before { login_user user }
  end

  shared_examples_for 'スペースが0件' do
    it 'もっと見るのパスが含まれない' do
      render
      expect(rendered).not_to match("\"#{Regexp.escape(spaces_path)}\"")
    end
    it 'スペース作成のパスが含まれる' do
      render
      expect(rendered).to match("\"#{Regexp.escape(new_space_path)}\"")
    end
  end

  context '未ログイン' do
    it_behaves_like 'スペースが0件'
  end

  context 'ログイン中' do
    include_context 'login'
    it_behaves_like 'スペースが0件'
  end

  space_limit = 10
  shared_context 'create_spaces' do
    before do
      @create_spaces = FactoryBot.create_list(:space, space_limit + 1)
      @new_spaces = Space.all.order(id: 'DESC').limit(space_limit)
    end
  end

  shared_examples_for "スペースが#{space_limit + 1}件" do
    it '1番新しいスペース名が含まれる' do
      render
      expect(rendered).to match(Regexp.escape(@create_spaces[space_limit].name))
    end
    it "#{space_limit}番目に新しいスペース名が含まれる" do
      render
      expect(rendered).to match(Regexp.escape(@create_spaces[1].name))
    end
    it "#{space_limit + 1}番目に新しいスペース名が含まれない" do
      render
      expect(rendered).not_to match(Regexp.escape(@create_spaces[0].name))
    end
    it '1番新しいスペースのパスが含まれる' do
      render
      expect(rendered).to match("//#{@create_spaces[space_limit].subdomain}.#{Settings['base_domain_link']}")
    end
    it "#{space_limit}番目に新しいスペースのパスが含まれる" do
      render
      expect(rendered).to match("//#{@create_spaces[1].subdomain}.#{Settings['base_domain_link']}")
    end
    it "#{space_limit + 1}番目に新しいスペースのパスが含まれない" do
      render
      expect(rendered).not_to match("//#{@create_spaces[0].subdomain}.#{Settings['base_domain_link']}")
    end
    it 'もっと見るのパスが含まれる' do
      render
      expect(rendered).to match("\"#{Regexp.escape(spaces_path)}\"")
    end
    it 'スペース作成のパスが含まれる' do
      render
      expect(rendered).to match("\"#{Regexp.escape(new_space_path)}\"")
    end
  end

  context '未ログイン' do
    include_context 'create_spaces'
    it_behaves_like "スペースが#{space_limit + 1}件"
  end

  context 'ログイン中' do
    include_context 'login'
    include_context 'create_spaces'
    it_behaves_like "スペースが#{space_limit + 1}件"
  end
end

spec/requests/top_spec.rb
rspecで落ちてた下記を削除

      it 'use index template' do
        get root_path, headers: header_hash
        should render_template('index')
      end
      space_limit = 10
      it "新しいスペースが#{space_limit}件取得できる" do
        FactoryBot.create_list(:space, space_limit + 1)
        new_spaces = Space.all.order(id: 'DESC').limit(space_limit)
        get root_path, headers: header_hash
        expect(assigns(:new_spaces)).to match_array new_spaces
      end

代わりに下記を追加

  describe 'GET #index @new_spaces' do
    shared_context 'スペース作成' do |limit|
      before { @create_spaces = FactoryBot.create_list(:space, limit) }
    end

    shared_examples_for 'ベースドメイン、1番新しいスペース' do
      it '名前が含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include(@create_spaces[@create_spaces.count - 1].name)
      end
      it 'パスが含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include("//#{@create_spaces[@create_spaces.count - 1].subdomain}.#{Settings['base_domain_link']}")
      end
    end
    shared_examples_for "ベースドメイン、#{Settings['new_spaces_limit']}番目に新しいスペース" do
      it '名前が含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include(@create_spaces[@create_spaces.count - Settings['new_spaces_limit']].name)
      end
      it 'パスが含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include("//#{@create_spaces[@create_spaces.count - Settings['new_spaces_limit']].subdomain}.#{Settings['base_domain_link']}")
      end
    end
    shared_examples_for "ベースドメイン、#{Settings['new_spaces_limit'] + 1}番目に新しいスペース" do
      it '名前が含まれない' do
        get root_path, headers: base_headers
        expect(response.body).not_to include(@create_spaces[@create_spaces.count - (Settings['new_spaces_limit'] + 1)].name)
      end
      it 'パスが含まれない' do
        get root_path, headers: base_headers
        expect(response.body).not_to include("//#{@create_spaces[@create_spaces.count - (Settings['new_spaces_limit'] + 1)].subdomain}.#{Settings['base_domain_link']}")
      end
    end

    shared_examples_for 'ベースドメイン、スペースがない' do
      it 'ベースドメイン、もっと見るのパスが含まれない' do
        get root_path, headers: base_headers
        expect(response.body).not_to include("\"#{spaces_path}\"")
      end
    end
    shared_examples_for 'ベースドメイン、スペースがある' do
      it 'ベースドメイン、もっと見るのパスが含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include("\"#{spaces_path}\"")
      end
    end

    shared_examples_for 'ベースドメイン' do
      it 'スペース作成のパスが含まれる' do
        get root_path, headers: base_headers
        expect(response.body).to include("\"#{new_space_path}\"")
      end
    end

    shared_examples_for 'スペースが0件' do
      it_behaves_like 'ベースドメイン、スペースがない'
      it_behaves_like 'ベースドメイン'
    end
    shared_examples_for 'スペースが最大表示数と同じ' do
      include_context 'スペース作成', Settings['new_spaces_limit']
      it_behaves_like 'ベースドメイン、1番新しいスペース'
      it_behaves_like "ベースドメイン、#{Settings['new_spaces_limit']}番目に新しいスペース"
      it_behaves_like 'ベースドメイン、スペースがある'
      it_behaves_like 'ベースドメイン'
    end
    shared_examples_for 'スペースが最大表示数より多い' do
      include_context 'スペース作成', Settings['new_spaces_limit'] + 1
      it_behaves_like 'ベースドメイン、1番新しいスペース'
      it_behaves_like "ベースドメイン、#{Settings['new_spaces_limit']}番目に新しいスペース"
      it_behaves_like "ベースドメイン、#{Settings['new_spaces_limit'] + 1}番目に新しいスペース"
      it_behaves_like 'ベースドメイン、スペースがある'
      it_behaves_like 'ベースドメイン'
    end

    context '未ログイン' do
      it_behaves_like 'スペースが0件'
    end
    context 'ログイン中' do
      include_context 'ログイン処理'
      it_behaves_like 'スペースが0件'
    end

    context '未ログイン' do
      it_behaves_like 'スペースが最大表示数と同じ'
    end
    context 'ログイン中' do
      include_context 'ログイン処理'
      it_behaves_like 'スペースが最大表示数と同じ'
    end

    context '未ログイン' do
      it_behaves_like 'スペースが最大表示数より多い'
    end
    context 'ログイン中' do
      include_context 'ログイン処理'
      it_behaves_like 'スペースが最大表示数より多い'
    end
  end

内容は、テスト仕様書を書く時の検証項目を想定して、組み合わせパターンと境界値等で書いています。
実装前にテスト仕様書を作り、テスト駆動にするのが私の理想です。
そして、ユニットテストの正しさを検証する為に手動テストを1回だけ行う。
1度手動でテストした所は、2回目は行わなくても担保できる。

【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/184ff1498e734e24346e2290352a7e27bb298c84

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です