【RSpec / Rails】画像投稿機能の結合テストコード

## 初めに

前回の<a href="https://qiita.com/study_matome/items/bb396a58d6bf78c5968f">結合テストコードの書き方（新規登録に関するテストコード）</a>に引き続き
今回は画像投稿機能の結合テストコードを実装しました。
次の機会に行う際、抜け漏れがないよう記録していきたいと思います。

## 結合テストコードを書く手順

### ①結合テストコードを書くためのファイルを生成する

今回は画像投稿機能に関する結合テストコードを書いていきます。

```
% rails g rspec:system items
```
生成されたファイル
spec/system/items_spec.rb

---
以下のようなファイル構成になっていれば成功です。
```
 🗂　　spec
 　　∟　　　　🗂 factories
 　　　　　　　　🗂 models
 　　　　　　　　🗂 requests
　　　　　　　　 🗂 system
 　　　　　　　　　　∟ 　users_spec.rb  ←前回生成したファイル
 　　　　　　　　　　∟ 　items_spec.rb  ←生成されたファイル

```

### ②exampleを整理する

ユーザー目線で考え、「ユーザーがブラウザでどのような操作をすると、どうなるのか」を考えます。

例　投稿に関する結合テストコード

・投稿できるとき
　　正しい情報を入力すれば投稿できてトップページに移動する
・登録ができないとき
　　誤った情報では投稿できずに投稿ページへ戻ってくる

この動作を１つ１つ細かく洗い出して、テストコード内に落とし込みます。


### ③「ログインする」という流れをサポートモジュールにまとめる

今後投稿機能の他に、編集機能や削除機能を追加しようと考えています。
全ての機能で「ログインしている場合」という条件が出てくるため、
「ログインする」という流れをサポートモジュールにまとめます。

詳しくは以下の記事でご紹介しています。
<a href="https://qiita.com/study_matome/items/6965ab99a1a4539f8f06">【Rails/System Spec】サポートモジュールで結合テストコードの記述を短くする（ログイン動作をまとめる）</a>

### ③洗い出した条件を書く

#### :o:　条件がイメージがしづらい時

実際にアプリで「新規投稿」をしてみて、「どのページにいるか」「どのボタンを押すと遷移するか」「どこに何を入力する必要があるか」などを意識して操作すると考えやすくなるのでおすすめです。

----
※FactoryBotで新規登録(@user)、新規投稿(@item)に必要な情報を定義しておきます。

```spec/system/items_spec.rb
require 'rails_helper'

RSpec.describe '新規投稿', type: :system do
  before do
    @user = FactoryBot.create(:user)
    @item = FactoryBot.create(:item)
  end
  context '新規投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # トップページに移動する
      # ログインする
      # 投稿ページに移動する
      # フォームに情報を入力する
      # 送信するとItemモデルのカウントが1上がることを確認する
      # トップページに遷移する
    end
  end
  context '新規投稿ができないとき'do
    it 'ログインしていないと新規投稿ページに遷移できない' do
      # トップページに遷移する
      # 新規投稿ページへのボタンがないことを確認する
    end
  end
end
```

中身を書く前にテストコードを実行します。

```
% bundle exec rspec spec/system/items_spec.rb
```

![スクリーンショット 2022-06-01 14.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/e4078d4b-eaab-b471-c2a6-75eafad548b0.png)
緑色の表示の場合は、テストが正しく通ったことを示しています。
次は中身を書いていきましょう。

---
##### 補足：なぜ中身を書く前に、テストコードを実行するの？
---

理由はエラーの特定がしやすくなるためです。
テストコードは入れ子構造を使っているため、endが抜けるなど文法エラーが出やすい箇所だと感じています。

例　endが足りない場合のエラー
![スクリーンショット 2022-05-31 14.53.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/89ebc944-c6b0-4b50-bbfe-88d5c8f95822.png)
 続き　syntax error, unexpected end-of-input, expecting end

---

１度テストコードを実行することで「ここまではエラーはなし」という確認につながるので、
もし以降にエラーが出た場合「この記述以降の箇所でのエラー」と、特定がしやすくなります。


### ④ 実際の結合テストコード


```spec/system/items_spec.rb

require 'rails_helper'

def basic_pass(path)               #--①説明
  username = ENV['BASIC_AUTH_USER'] 
  password = ENV['BASIC_AUTH_PASSWORD']
  visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{path}"
end

RSpec.describe '新規投稿', type: :system do
  before do
    @user = FactoryBot.create(:user)
    @item = FactoryBot.build(:item)
  end

  context '新規投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # ログインする
      sign_in(@user)
      # 投稿ページに移動する
      visit new_item_path
      # フォームに情報を入力する
      attach_file '作品', "#{Rails.root}/spec/fixtures/test_sample.png" #--②説明
      fill_in 'コメント', with: @item.text
      fill_in '作った年齢（半角数字）', with: @item.age
      fill_in '材料', with: @item.material
      fill_in '作り方', with: @item.making
      # 送信するとItemモデルのカウントが1上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { Item.count }.by(1)
      # トップページに遷移する
      visit root_path
    end
  end
  context '新規投稿ができないとき'do
    it 'ログインしていないと新規投稿ページに遷移できない' do
      # トップページに遷移する
      basic_pass root_path
      # 新規投稿ページへのボタンがないことを確認する
      expect(page).to have_no_content('投稿する')
    end
  end 
end
```



--① Basic認証
<a href="https://qiita.com/taka_no_okapi/items/b4cab8e2a451b3f1b88e">Basic認証を交えたテストコードの書き方</a>を参考にさせていただきました。

---

--② Active Storageを使用した画像添付
<a href="https://teratail.com/questions/370309">画像更新のテストが通らない</a>という質問を参考にさせていただきました。

#### 具体的な方法

①specディレクトリに、fixturesディレクトリを作成し、画像を配置する

```
 🗂　　spec
 　　∟　　　　🗂 factories
 　　　　　　　　🗂 models
 　　　　　　　　🗂 requests
     🗂 fixtures         ←ディレクトリを作成する
      ∟ test_sample.png  ←画像を配置する（画像名は任意でOK）
　　　　　　　　 🗂 system
 　　　　　　　　　　∟ 　users_spec.rb  
 　　　　　　　　　　∟ 　items_spec.rb  ←今回生成したファイル

```

②Active Storageを使用した記述を追加


```spec/system/items_spec.rb
attach_file '作品', "#{Rails.root}/spec/fixtures/test_sample.png"
#''内はラベル名を入力 
```
※ディレクトリ名や画像名は適宜該当する名前に置き換えて記述ください。
※ラベル名に該当する場所が分からない場合は<a href="https://qiita.com/study_matome/items/836691b6242dbdd5dcb9">こちらの「実際にフォームへの入力を行う」</a>をご参照ください。

### ⑤テストコードを実行する

```
% bundle exec rspec spec/system/items_spec.rb
```
![スクリーンショット 2022-06-01 14.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/e4078d4b-eaab-b471-c2a6-75eafad548b0.png)


テストが正しく通ったことを示す緑色の表示の場合は完了です。
お疲れ様でした:exclamation:


## まとめ

最後までご覧くださり、ありがとうございました。
今回は投稿機能の結合テストコードの実装記録でした。

初学者のため、記入漏れや記述ミスがありましたら教えていただけると助かります。

こちらの記事がどなたかの参考になりましたら幸いです。



## 関連

<a href="https://qiita.com/study_matome/items/6965ab99a1a4539f8f06">【RSpec / Rails】サポートモジュールで結合テストコードの記述を短くする（ログイン動作をまとめる）</a>
<a href="https://qiita.com/study_matome/items/836691b6242dbdd5dcb9">【Rails/System Spec/Capybara】結合テストコードを書くときによく使う表現 一例</a>
<a href="https://qiita.com/study_matome/items/bb396a58d6bf78c5968f">【Rails】結合テストコードの書き方（新規登録に関するテストコード）</a>