初めてのRSpecで学んだこと

課題で出てきて、初めて取り組んだRSpec！
色々なポイントを学んだので備忘録として残しておく。
初学者なので、間違ってる点などあればご指摘下さい。

## バージョン
- ruby 3.2.2
- Rails 6.1.7.6
-------------------------

作成しているアプリはタスク管理アプリ

## SystemSpecの基本
### Factoryを使用したテスト
Factoryとは、railsでテストをする時用のテストデータを作成してくれるテンプレートのこと。
[`factory_bot_rails`](https://github.com/thoughtbot/factory_bot_rails) というgemをインストールすることで使用できるようになる。
（Factoryを使用する手順（インストール方法など）は今回は省略。）
今回のタスク管理アプリで、「一覧画面に遷移した場合」→「作成済みのタスク一覧が表示される」というテストコードを書く際、Factoryを使用した。

```spec/factories/task_spec.rb
FactoryBot.define do
  factory :task do
    name { 'パパ' }
    content { '日曜日歯医者' }
  end
end
```
まず、 `spec/factories/task_spec.rb` の中に、テストデータの定義的なものを書く。
上記のように書くことで、テストデータの基本内容は、 `name`  が、「パパ」、 `content` が「日曜日歯医者」となる。

```spec/system/task_spec.rb
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
  describe '一覧表示機能' do
    context '一覧画面に遷移した場合' do
      it '作成済みのタスク一覧が表示される' do
        FactoryBot.create(:task)
        visit tasks_path
        expect(page).to have_content '日曜日歯医者'
      end
    end
  end
end
```
このコードの説明。
６行目の
```
FactoryBot.create(:task)
```
の一文の中の「:task」によって、 `spec/factories/task_spec.rb` の中の、2行目
```
factory :task do
```
の部分の `task` が繋がり、 `spec/factories/task_spec.rb` で定義した内容を元にテストデータが作成される。
この場合、 `name` が、「パパ」、 `content` が「日曜日歯医者」というテストデータとなる。
なので８行目の
```
expect(page).to have_content '日曜日歯医者'
```
の一文で、「日曜日歯医者」の文字がページの中に含まれているかを確認しており、このテストは成功すれば、プログラムは正しいということ。

また、以下のような書き方もある。

```spec/system/task_spec.rb
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
  describe '一覧表示機能' do
    context '一覧画面に遷移した場合' do
      it '作成済みのタスク一覧が表示される' do
        FactoryBot.create(:task, content: '日曜日買い物')
        visit tasks_path
        expect(page).to have_content '日曜日買い物'
      end
    end
  end
end
```
違いは６行目で 
```
FactoryBot.create(:task, content: '日曜日買い物')
```
「content: '日曜日買い物'」が有るかどうか。
このように `content: '日曜日買い物'` を入れることで、 `spec/factories/task_spec.rb` で定義した基本のテストデータ、 `name` が、「パパ」、 `content` が「日曜日歯医者」というのを
`name` が、「パパ」、 `content` が「日曜日買い物」というテストデータに変えることができる。

### 「タスクを新規作成した場合、新規登録が正常に完了するか」というテストのコード
これを考える際、私は
```
require 'rails_helper'
RSpec.describe 'タスク管理機能', type: :system do
  describe '新規作成機能' do
    context 'タスクを新規作成した場合' do
      it '新規登録が正常に完了する' do
        FactoryBot.create(:task)
        visit task_path(Task.last)
        expect(page).to have_content ’投稿を作成しました！’
        expect(page).to have_content '日曜日歯医者'
```
とすると、エラーになってしまった💦「投稿を作成しました！」なんて無いよーと言ってます。

![スクリーンショット 2023-11-25 15.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566175/1ac959be-7e3a-42e0-b0aa-172881438aa0.png)

この「’投稿を作成しました！’」というのは
```app/controllers/tasks_controller
def create
    @task = Task.new(task_params)
      if @task.save
        redirect_to task_path(@task.id), notice: "投稿を作成しました！"
      else
        render :new
      end
end
```
上記のように、新規タスク作成した時に、 `notice` にて、投稿を作成しました、と出るようにしていたので、新規作成後の遷移したページに「投稿を作成しました！」という表示があれば、テストできるのではないかと考えたのですが、
なぜ、これではテストに失敗してしまうのかというと
##### このFactoryBotで作成されたテストデータによって作成されたページというのは、`tasks_controller` の中の `create` アクションは通過していない！！そのため、「投稿を作成しました！という文は無い！　
とメンターさんに教えてもらいました！！なるほど！！確かにそうだ！！

ということで、この新規作成完了のテストは `FactoryBot` は使わず
```
describe '新規作成機能' do
  context 'タスクを新規作成した場合' do
    it '作成したタスクが表示される(新規登録が正常に完了する)' do
      visit new_task_path
      fill_in 'task_name', with: 'パパ'
      fill_in 'task_content', with: '日曜日歯医者'
      click_on 'Create Task'
      expect(page).to have_content '日曜日歯医者'
    end
  end
end
```
というコードに書き直し、無事課題をクリアすることができました！
ちなみに、この `fill_in` を使用する際にもポイントがあり、
```
fill_in 'task_name', with: 'パパ'
fill_in 'task_content', with: '日曜日歯医者'
```
この `task_name` と `task_content` の部分を、
```
fill_in 'name', with: 'パパ'
fill_in 'content', with: '日曜日歯医者'
```
というように、カラム名をそのまま書きがちだが、これだとエラーになることがあるとのこと。
カラム名そのままでなく、Railsが自動で作成してくれているIDを用いて指定すると、うまくいく。

![スクリーンショット 2023-11-25 15.46.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566175/a04ba331-c484-eb97-def4-3ddfbeeddec7.png)

RSpecについての学びはこれで以上〜！お疲れ様でした！！



ちなみに、RSpecのこと以外でも、面白い学びがあったので、それも書き残しておく。
```
visit task_path(Task.last)
```
この、 `task_path(Task.last)` の部分。
`task_path` 　って、
`task_path(task.id)` 　というように、後に `id` を指定して、 `path` の先を指定するイメージだったけど、今回は、 `task_path(Task.last)` というように、 `id` を指定していないのにうまくプログラムが動くのが疑問だったので、調べてみた。

まず、[Railsガイド](https://railsguides.jp/active_record_querying.html)で、 `last` メソッドの使い方を調べてみた。
`last` とはモデルの最後のレコードを取得するメソッドである。

![スクリーンショット 2023-11-26 15.22.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159704/f01aaef9-84c6-7c13-6f78-045c71faecf4.png)


Railsガイドによると、 `id` も含めて、最後のレコード全体を取得しているのがわかるけど、なんでこれで `id` を取得できるのかが疑問だったのでメンターさんに聞いてみた。
すると、
Railsが、このデータ全体から `id` のみを取得してくれる、とのこと！！　Railsの機能らしい！！
おー！そうなんだ！
なので、実は、 `task_path(task.id)` というのも、 `task_path(task)` としてしまっても、きちんと動くのだそう！！
へぇーーー！そうだったんだ！！
初学者の私にとっては、とっても面白く、１００「へぇ」くらいの学びでした！（笑）

本日は以上！お疲れ様でした！