railsのテストディレクトリ構造とテスト処理

#railsのテストディレクトリ
テストとは開発をしながら、動作するかテストすること。テストディレクトリにはテストに必要なファイルがある。

###models(モデルテスト)
モデル名_test.rbに記述するテスト。(例 test/models/user_test.rb)

rails g model ~でモデルが作られると
testディレクトリにそのモデルのためのテストができる

書き方
まずモデルのインスタンスを作成する(主にseup関数で行う)
↓
そのインスタンスが機能しているかや、複数のインスタンスの関係性が機能しているかなど確認する。

```ruby:test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup #インスタンス作成
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid? #このテストの場合Userファイルで書いたvalidateが発動しているかテストしている
  end
end
```

###controllers(コントローラーテスト)
controller_test.rbに記述するテスト。

rails g controller ~でコントローラーが作られると
testディレクトリにそのコントローラーのためのテストができる

書き方
まず必要な処理をsetupで書く
↓
どのアクションを発動させるためにどのURLを発信するかを書き、assert関数でテスト内容を書く。
integration testとの違いは一つのアクション内で完結するテストということ。

```ruby:test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
  ・
  ・
  end

  test "should get new" do
    get users_new_url
    assert_response :success
  end
end
```

###integration(統合テスト)
test/integration/統合テスト名_test.rbに記述するテスト。

rails g integration_test 〜でtestディレクトリに作られる。

書き方
まず必要な処理をsetupで書く
↓
どのアクションを発動させるためにどのURLへ発信するかを書き、assert関数でテスト内容を書く
様々なURLへ発信して、如何にも実際に手で動かしているテストのように行う。

```ruby:test/integration/microposts_interface_test.rb
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
  ・
  ・
  end

  test "micropost interface" do
  get root_path
  assert ...
  ・
  ・
  post microposts_path ...
  assert ...
  ・
  ・
  end
```

機能テストとの違いは一つのコントローラーのアクション内でのテストではなく、rootingを通して様々なコントローラーに繋いでどうなるかなどをテストする

###mailer(メールテスト)
メーラーを作成すると自動で以下のファイルが作成される。

・preview
これはメールの内容を視覚的にブラウザで確認するためにある

```ruby

# Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
  def account_activation
    user = User.first
    user.activation_token = User.new_token
    UserMailer.account_activation(user)
  end
#これはhttp://localhost:3000/rails/mailers/user_mailer/account_activationにアクセスするとpreviewのaccount_activationが発動し、
#UserMailer.account_activation(user)の結果を確認できるってこと
```

・mailerテスト
メール内容に特定の要素は存在するかなどを確認する

###helpers(単体テスト)
上記のテストでは実施しにくいテストを行う。上記のテストより細部に関するテストと言える。app内で定義した関数処理がうまく作動しているかなどを確認する。
以下の例ではfull_title関数が正常に動作している確認している、

```
  test "full title helper" do
    assert_equal full_title, "Ruby on Rails Tutorial Sample App"
    assert_equal full_title("Help"), "Help | Ruby on Rails Tutorial Sample App"
  end
```

###fixtures
テストで使うためのデータベースにあるデータとして記述される。ymlファイルに記述

###test_helper.rb
全てのtestはtest_helper.rbを導入している。test_helper.rbの中にはtestで使う関数を書いている。
またappで使用している関数(app/helpersで定義されている)をtest環境でも使用したい場面がある。そんな時はapp/helpersにある関数定義ファイルをtest_helper.rbにincludeすることがある。




#補足
#####setup関数
テストファイルのsetup関数で変数を作り、テスト内で採用する。

```ruby:test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end
```

#####データ変更後、データの値チェックをしたい時(reload)
テストの中でデータ変更を行った場合、reloadでデータ更新をしてから、値チェックをする。

```ruby
 test "password reload" do
    log_in_as(@other_user)
    patch user_path(@other_user), params: {
                                    user: { password:              @other_user.password,
                                            password_confirmation: @other_user.password}}
    assert_not @other_user.reload.password #patchでデータ送信、更新後にインスタンスの中身を見たい時はreloadをしないといけない
  end
```

#####テストで作ったインスタンス変数の値を知りたい時(assigns)
controllerのアクション内で作成されたインスタンス変数のプロパティーの値を、テスト内で確認したい時、assigns()を使用する。assigns(インスタンス変数).データカラムとすることで確認できる。

```ruby:controller
  def create
    @user = User.find_by(email: params[:email]
  end
```

```ruby:test
  def "create test" do
    .
    .
    user = assigns(:user) 
    #@userというインスタンスが存在すれば、assigns(:user)でインスタンスのデータにアクセスできる。assigns(@user)ではだめ
    .
    .
  end
```



######自動テスト
開発と同時並行で自動でテストする方法がある。開発で変更を加えるたびに自動でテストを行ってくれる。そのためわざわざテストコマンドを毎回打たなくて済む。

railsでは自動テストを導入するためにはGuardを取り入れる
↓
Guard fileに自動テストするように指示を書く
詳しくは[Ruby on Rails チュートリアル](https://railstutorial.jp/chapters/static_pages?version=5.1#cha-static_pages)

注意
Guardを使うときにspringという機能を使う
しかしspringがgitとの競合をしないように、.git ignoreファイルに、springを書きgitリポジトリに保存されないようにする



#参考文献
[Ruby on Rails チュートリアル](https://railstutorial.jp/chapters/static_pages?version=5.1#cha-static_pages)
[単体テスト・結合テスト・総合テストの違い、観点や注意点を簡単に説明する](https://pm-rasinban.com/ut-it-st)
[Rails チュートリアル　【初心者向け】　テストを10分でおさらいしよう！](https://qiita.com/duka/items/2d724ea2226984cb544f)