Rspecのあれこれ

どうもチャンクノです！
最近個人的なやつだったり、企業の課題などでrspecを書いていたので備忘録に🙆‍♂️

あんまり書き方知らなそうなやつだけピックアップしようと思います。

#userがログインしてるかどうか
大体のサービスがユーザーがログイン状態でない場合はできることを制限していると思います。
で、ログインしてるかどうかは下記の記事の通り、自分でメソッドを作ります。
typeによって変わるのでご注意を!！
自分はrequest派です。
https://qiita.com/kazuooooo/items/1677f2a3bddf3a8df23f

```
rails-helper.rb

RSpec.configure do |config|
  Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } #support directoryをrequire
  config.include RequestSpecHelper, type: :request #type: :requestのときにRequestHelperをinclude
end
```

```
spec/support/request_spec_helper.rb

module RequestSpecHelper

  include Warden::Test::Helpers

  def self.included(base)
    base.before(:each) { Warden.test_mode! }
    base.after(:each) { Warden.test_reset! }
  end

  def sign_in(resource)
    login_as(resource, scope: warden_scope(resource))
  end

  def sign_out(resource)
    logout(warden_scope(resource))
  end

  private

  def warden_scope(resource)
    resource.class.name.underscore.to_sym
  end

end
```
テストはこんな感じ。

```
RSpec.describe "Trades", type: :request do
  describe "#index" do
    context "ユーザー登録している場合" do
      let(:user) { create(:user) }
      it "200ステータスを返す" do
        sign_in user <= これでログインしてることにできる。
        get user_trades_url
        expect(response).to have_http_status "200"
      end
    end
  end
end
```

#コントローラーへのparamsの渡し方
ここもtypeによって記述方法が変わります。
自分はrequest派

```
RSpec.describe 'Categories', type: :request do
  describe '#create' do
    let(:category) { FactoryBot.attributes_for(:category, ideas_attributes: { body: 'idea' }) }
     # accepts_nested_attributes_forを使ってる場合はこう書くよ

    context '成功した場合' do
      it '201ステータスを返す' do
        expect do
          post api_v1_categories_url, params: { category: category }
          # 検索のテストもこんな感じで書くよ。
        end.to change(Category, :count).by(1)
        expect(response.status).to eq(201)
      end
    end
  end
end
```

```
RSpec.describe "Trades", type: :request do
  describe "#edit" do
    context "自分のトレードの場合" do
      let(:trade) { create(:trade) }
      let(:user_profile) { create(:user_profile, user: trade.user) }
      it "200ステータスを返す" do
        sign_in user_profile.user
        get edit_user_trade_url(trade) <= paramsの渡し方違うので気をつけて
        expect(response).to have_http_status "200"
      end
    end
  end
end
```

#アソシエーション
これはfactorybotというgemをインストールする必要があります。
参考にどうぞ
https://qiita.com/Ushinji/items/522ed01c9c14b680222c

```
FactoryBot.define do
  factory :user_profile do
    nickname { "神" }
    avatar   {Rack::Test::UploadedFile.new(Rails.root.join('spec', 'fixtures', '1.jpg'), 'image/jpg')}
    association :user <= これだけ
　　user.rbにユーザーを定義してないとエラーになるので気をつけましょう。
  end 
end
```

```
let(:user_profile) { create(:user_profile) }
# これでユーザーも一緒に作られます。
```

注意点としては親と子モデル両方にassociationの記述をしちゃうとお互いがお互いを永遠に作りあってエラーになるので気をつけましょう。
何かいい方法ないかな🙄

#テストデータに画像を入れる
自分はこの記事を参考にしました！!
https://hyperneetprogrammer.hatenablog.com/entry/2017/11/06/173103

#APIテスト
基本的なところは普通のテストと変わらないと思います。
自分はこの記事を参考にしました！!
https://qiita.com/k-penguin-sato/items/defdb828bd54729272ad

```
RSpec.describe 'Ideas', type: :request do
  describe '#index' do
    let!(:category)        { create(:category) }
    let!(:second_category) { create(:second_category) }
    let!(:idea)            { create(:idea, category: category) }
    let!(:second_idea)     { create(:idea, category: category) }
    let!(:third_idea)      { create(:idea, category: second_category) }
    # ここはもっといい書き方があると思われる、、、。

    context '指定されたカテゴリーが存在する場合' do
      it '指定されたカテゴリーに紐付くアイデアを返す' do
        get api_v1_ideas_url, params: { name: 'アプリ' }
        json = JSON.parse(response.body) <= ここがポイントですね
        expect(json['data'].length).to eq(2)
      end
    end
  end
end
```

大体こんなところですかね🤥
rspec書けるようになりたいなら
https://blog.jnito.com/entry/2014/02/07/110505
ここで紹介してる本を買うのが一番手取り早いと思います。
自分もまだ読みきれていないですがここに書いた内容はほぼ全て記されています。

それでは今回はこの辺で！！
皆様よきプログラミングライフを🙏