【RSpec】で書く「Rails Tutorial　８章（後半：8.3）」のテスト

<br>
前回↓に引き続きRails TutorialをRSpecを使って進めました。
[【RSpec】で書く「Rails Tutorial　８章（前半：8.2.5まで）」のテスト](https://qiita.com/Goi350ml/items/1b58238dd28349825a8f)

前半として変な位置で区切ってしまったため、
今回はSessionのログアウトのみです..

***
###Rails Tutorial８章（8.3.1）ですること
 - Sessionのログアウト設定
 - Sessionのログアウトするテスト

***
###使用ファイル
 - Spec（Feature）
 - Spec（Factory）
 - Controller（Session）
 - Helper（Session）


####Spec（Feature）
```ruby:spec/features/sessions_spec.rb
require 'rails_helper'

RSpec.feature "Sessions", type: :feature do

  before do
      @user = FactoryBot.create(:user)
  end
  describe "<sessions#destroy>" do

    before do
      #ログインします
      visit login_path

      fill_in "Email", with: @user.email
      fill_in "Password", with: @user.password
      click_button "Log in"
    end

    scenario "ログアウトした後にメニューバーの表示内容が変わること" do
      #Request Specでの書き方が分からなかったためFeatureに書きます...

      #ログアウトします
      visit root_path
      click_link "Log out"
      expect(page).to have_current_path(root_path)

      expect(page).to have_css("a", text: "Log in")
      expect(page).to_not have_css("a", text: "Log out")
      expect(page).to_not have_css("a", text: "Profile")
    end
  end
end

```

####Spec（Factory）
```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name "Example User"
    email "user@example.com"
    password "foobar"
    password_confirmation "foobar"
  end
end

```

####Controller（Session）
```ruby:app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  #他記述
  ・
  ・

  def destroy
    log_out
    redirect_to root_url
  end
end

```

####Helper（Session）
```ruby:app/helpers/sessions_helper.rb
module SessionsHelper
  #他記述
  ・
  ・
  def log_out
    session.delete(:user_id)
    @current_user = nil
  end
end

```


***
##質問
###Spec（Request）で書く場合

Rails Tutorial(8.3.1)のMinitestのテストでは
インテグレーションテスト（RSpecだとFeature）でした。

ただ、好奇心でRequestでテストを書いてみようと思いトライしたのですが
まんまと沼にどハマりしてしまいまして...

何とか以下の記述が近いのではないかと思い実装したのですが、
結果はエラー発生でテストできていません。

>"!session[:user_id]"をテストしたらFalseを想定しているのですが、返り値がtrueになってしまいます。

*user_id = nil*の部分でうまく"nil"が入っていない記述の問題でしょうか？
または、テストの仕方自体に問題があるのでしょうか？

その辺りが明確ではないため教えていただけると助かります。。

```ruby:spec/requests/sessions_spec.rb
  # #8.3.1
  #ログアウト
  describe "<request#destory>" do
    #ユーザーがログインした状態にする
    before do
      #@userにユーザー情報を登録
      @user = FactoryBot.build(:user)
      #User.find_byが呼ばれた際に@userを返す
      allow(User).to receive(:find_by).and_return(@user)
      #ログイン完了
    end

    context "ユーザーがログアウトした時" do
      it "falseを返すこと" do

        user = @user
        user_id = nil

        delete logout_path
        expect(!session[:user_id]).to be_falsey
      end
    end
  end
```

####発生するエラー
![スクリーンショット 2018-10-28 12.42.07.png](https://qiita-image-store.s3.amazonaws.com/0/260354/9d300df0-ab5f-94d9-8138-c164259129bc.png)


***
####まとめ・反省点
どうもSessionあたりの内部構造をテストする際のController（Request）の記述が理解できていないと感じました。
動作が理解できていないのか、記述が間違えているのか、その辺りが課題になりそうです。

また、RequestとFeatureの使い分けもはっきりと答えが分かっていません。
こちらは実際の業務を通して学ぼうと考えています。

何となくRSpec分かってきたつもりでしたけど、まだまだだと痛感しました。。
mockやstub、shared、subjectも使っていないのは理解していないからですね。。

早くRSpecをぶん回してテスト任せてくださいって言えるようになりたいので
指摘・アドバイス・マサカリ等よろしくお願いします。
<br>

***
###変更履歴
10/29
SessionのログアウトのRequestテストが完成（多分）しました。

```ruby:spec/requests/users_login_api_spec.rb
  #8.3.1
  #ログアウト
  describe "<request#destory>" do
    #ユーザーがログインした状態にする
    before do
      #@userにユーザー情報を登録
      @user = FactoryBot.build(:user)
      #User.find_byが呼ばれた際に@userを返す
      allow(User).to receive(:find_by).and_return(@user)
      #ログイン完了
    end

    context "ユーザーがログアウトした時" do
      it "falseを返すこと" do

        delete logout_path

        #be_falsey → nilか空白であればfalseです
        expect(response).to have_http_status(302)
        expect(session[:user_id]).to be_falsey # => nil
      end
    end
  end
```

どうでしょうか。一応このテストは全てGREENになります。
もしマッチャの使用場所が違う場合は速やかにご指摘ください。
<br>