Minitestでrailsのテストを書こう

# 1 対象読者：　テストって何？という人
テストってなんぞや？
ってところから本を読んで実装していったのでまとめます。
railsチュートリアルをやってもテストの概念がわからなかった人向けです。
RSpecの記事は充実しているけれど、Minitestの記事ってあんまりないのです。

テストとはシステムがちゃんと動くか確かめるコードのことです。
せっかく作ったけど、このボタン押せばこっちの画面ちゃんと出るかなーって時、
ブラウザで確かめるのもよいのですが、複雑な仕様になると
思わぬミスを発見できないこともありますよね。
というかいちいち```rails s```しなおすのめんどくさい！
そんなときにテストコードを書いて自動化しましょう。

# 2 準備しましょう
まずはちょいちょいっとテーブル用意
今回はユーザー一人につき、多数のブログを持つ１対N形式で進めていきます。
```$ rails new TestBlog```
```$ rails g model User name:string```
```$ rails g model Blog user_id:integer title:string body:string```
```$ rails g controller users show```
```$ rails g controller blogs show new```
```$ rake db:migrate```

ほいっと。あっという間にユーザーとブログのモデルとコントローラができましたっ！

ついでにroutes.rbも編集してあげてあげましょう。
```root 'users#show'
 resource :user
 resources :blogs```

ほい。rails sすると次の画面になるはずですっ！！

<img width="674" alt="初期画面.png" src="https://qiita-image-store.s3.amazonaws.com/0/280131/67321f7c-e5b6-e61c-b5ff-1a62cd080313.png">



# 3 データベースにテストデータをいれましょう。

ディレクトリからtest/fixturesを探しましょう。
fixturesにはダミーデータを入れていきます。
今回は一人のユーザー「シマリス」が、多数のブログを持っている設定です。

```
test/fixtures/users.yml

one:
  id: 1
  name: シマリス

```
ブログのデータも入れてみましょう。

```
test/fixtures/blogs.yml

one:
  id: 1
  user_id: 1
  title: おいしいくるみ料理の作り方
  body: くるみはそのままでおいしいです。

two:
  id: 2
  user_id: 1
  title: どんぐり集めの穴場
  body: 小学校あたりがおすすめです。

three:
  id: 3
  user_id: 1
  title: くるみVSどんぐり！
  body: どちらもおいしいです。
```
モデルのアソシエーションも忘れずに編集します。

```
app/models/user.rb

class User < ApplicationRecord
    has_many :blogs
end
```

```
app/models/blog.rb

class Blog < ApplicationRecord
    belongs_to :user
end
```

最後にディレクトリからconfig/database.ymlを開き、テスト環境と開発環境で使うDBを同じにします。

```
config/database.yml

development:
  <<: *default
  database: db/development.sqlite3

test:
  <<: *default
  #database: db/test.sqlite3
  database: db/development.sqlite3 　#<- ここをtestからdevelopmentに変更！

```

この状態でrake testのコマンドを打つと、fixtureに書いたデータがデータベースに入ります。
いちいち画面のフォームを整えなくともデータを簡単に入れられるのです☆
いよいよ準備が完了です。テストを書いていきましょう。

# 4 初めてのテスト

ターミナル上で　「rake test」と打つと、こんなテストが走るはずです。

```
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$ rake test
Run options: --seed 2422

# Running:

E

Error:
UsersControllerTest#test_should_get_show:
NameError: undefined local variable or method `users_show_url' for #<UsersControllerTest:0x0000000005f93558>
    test/controllers/users_controller_test.rb:6:in `block in <class:UsersControllerTest>'

bin/rails test test/controllers/users_controller_test.rb:5

~　略 ~

Finished in 0.282132s, 10.6333 runs/s, 0.0000 assertions/s.
3 runs, 0 assertions, 0 failures, 3 errors, 0 skips
```

最初に注目するのは最後の行に書いてあるこれ。
```3 runs, 0 assertions, 0 failures, 3 errors, 0 skips```

3つのテストが走り、３つのエラーがでましたよって意味になります。

テストなんていつ書いたの？って疑問もありますが、
実はrails g controllerしたタイミングで、
裏でrailsが勝手にそれっぽいテストを書いてくれています。
それがエラーになっているよって状態なんですね。

まずはこのエラーをつぶしていきましょう☆

テストのコントローラファイルを開くと、次のようなファイルが書かれているはずです。

```
test/controllers/users_controller_test.rb

  test "should get show" do
    get users_show_url
    assert_response :success
  end
```

「users#showページはちゃんと表示されるの？」っていうシンプルなテストです。
assertの直訳は「主張する」。
基本的な文法は assert "期待する振る舞い","実装コードのメソッド","テストデータの値"
実装コードのメソッドを使って、テストデータの値を入れてあげると、期待する振る舞いになるのか、テストをする。という文法構造ですね。

現在、エラーになっております。
理由は「users_show_url」なんて存在しないからですね。
rake routesでルートを確かめて、正しいurlを貼ってあげましょう。
「ユーザー「シマリス」のshowページに行きたい」というテストが以下のコードになります。

```
  test "should get show" do
    #get users_show_url
    get user_url(users(:one))
    assert_response :success
  end
```

それではテストしてみましょう。

```
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$ rake test
Run options: --seed 540

# Running:

〜 略　〜

.　　

Finished in 1.256377s, 2.3878 runs/s, 0.7959 assertions/s.
3 runs, 1 assertions, 0 failures, 2 errors, 0 skips
```

他の赤色のエラーの他に、緑色の「.」が現れたはずです。
これがテストが通った証拠ですね。無事シマリスのページがエラーなく表示されることをしめしています。

blogのコントローラのテストも修正し、テストが全て通る状態にしておきましょう。

```
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$ rake test
Run options: --seed 40446

# Running:

...

Finished in 1.150978s, 2.6065 runs/s, 2.6065 assertions/s.
3 runs, 3 assertions, 0 failures, 0 errors, 0 skips
```

# 5 createの成功テストを書こう

さあ、それでは、blogのcreateやdelete機能がちゃんと動くか、テストしてみましょう。
まずは普通にblogを投稿できるように、controllerやviewを編集しましょう。

```
controllers/users_controller.rb

class UsersController < ApplicationController

  def show
    @user = User.find(1)
  end
end
```

```
controllers/blogs_controller.rb

class BlogsController < ApplicationController
  def show
    @blog = Blog.find(params[:id])
  end

  def new
    @blog = Blog.new
  end

  def create
    @blog = Blog.new(blog_params)
    if @blog.save
      redirect_to user_path(1)
    else
      render :new, notice: 'もう一回試してみてください'
    end
  end

  private
  def blog_params
    params.require(:blog).permit(:user_id, :title, :body)
  end
end
```

```
views/users/show.html.erb

<%= @user.name %> のブログ一覧</br>
<% @user.blogs.each do |blog| %>
    title: <%= blog.title %>
    <%= link_to "本文を読む", blog_path(blog) %></br> 
<% end %>
<%= link_to '新しく記事を書く', new_blog_url(id: @user.id) %>
```

```
views/blogs/new.html.erb


<% @blog.errors.full_messages.each do |message| %>
    <div class="form-error">
         <%= message %>
     </div>
<% end %>

<%= form_for [ @blog ]  do |f| %>    
    title: <%= f.text_field :title %>
    body:  <%= f.text_field :body %>
           <%= f.hidden_field :user_id, value: params[:id] %>
           <%= f.submit '更新' %>
<% end %>

```
そしてblogのコントローラテストに次のような記述を書き加えます。

```
test/controllers/blog_controller_test.rb

  test "ブログを作ったらblogのモデル数が１増える" do
    get new_blog_url
    assert_response :success
    assert_difference 'Blog.count', 1 do
      post blogs_path, params: { blog: { 
                              user_id: 1,
                              title: '好きな果物',
                              body: "果物はスイカが好き！！",
                            } }
    end
    follow_redirect!
    assert_response :success
  end
end
```
期待する振る舞いは、

**１、newページに飛ぶ。**
**２、ブログを新しく作ったらblog数が１増える。**
**３、成功したらshowページにredirectする。**

の３つです。

ちなみに 「post」はコントローラのcreateを呼び出す機能です。
pathはrake routes　コマンドで確認しましょう。

できたらrake testしてみましょう。

```
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$ rake test
Run options: --seed 41181

# Running:

....

Finished in 0.883742s, 4.5262 runs/s, 6.7893 assertions/s.
4 runs, 6 assertions, 0 failures, 0 errors, 0 skips
```

全て通るはずです。
これで、ブログのcreate機能の品質は保証されましたね。
FailureやErrorが出てしまったら、慌てずにエラー文に従い、
テストコードや実装コードを見直してミスを探しましょう。

# 6 ブログ作成失敗のテストを書こう

しかし現実はいつも成功するとは限りませんよね。
validateなどであえて作成失敗させる場合もあります。
てことで、失敗するテストも書きましょう。
blogのコントローラーのテストに以下の表記を加えましょう。

```
test/controllers/blog_controller_test.rb

  test "タイトルが入っていなくてブログ作成に失敗する" do
    get new_blog_url
    assert_response :success
    assert_no_difference 'Blog.count' do
      post blogs_path, params: { blog: { 
                              user_id: 1,
                              title: '',
                              body: '果物はスイカが好き！！',
                            } }
    end
    assert_select "div",  "Title can't be blank"
  end
```

期待する振る舞いは、
**１、newページに飛ぶこと。**
**２、タイトルが入っていないのでテスト作成に失敗すること。**
**３、「Title can't be blank」というエラー文が表示されること。**
の３点です。
この状態でrake testするとこうなります。

```
Run options: --seed 34868

# Running:

...F

Failure:
BlogsControllerTest#test_タイトルが入っていなくてブログ作成に失敗する [/vagrant/TestBlog/test/controllers/blogs_controller_test.rb:32]:
"Blog.count" didn't change by 0.
Expected: 3
  Actual: 4


bin/rails test test/controllers/blogs_controller_test.rb:29

.

Finished in 0.801987s, 6.2345 runs/s, 9.9752 assertions/s.
5 runs, 8 assertions, 1 failures, 0 errors, 0 skips
```

失敗してしまいました。
つまり、今の実装コードでは、タイトルが空でもブログを作ってしまうため、
「タイトルが空だとブログ作成できない」という状態にならないのです。

そこで、実装コードをテストの期待する状態に近づけていきましょう。
具体的にはblogのモデルにvaridateを追加します。

```
app/models/blog.rb

class Blog < ApplicationRecord
    belongs_to :user
    validates :title, presence: true
end
```

これで、タイトルが空だったらブログ作成が失敗するようになりました。
rake testを走らせると？？

```
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$ rake test
Run options: --seed 49302

# Running:

.....

Finished in 0.944267s, 5.2951 runs/s, 9.5312 assertions/s.
5 runs, 9 assertions, 0 failures, 0 errors, 0 skips
vagrant@vagrant-ubuntu-trusty-64:/vagrant/TestBlog$
```

こうですね。
全て成功しました！

もちろんテストはこれだけではありません。
他にも様々な書き方がありますので、
気になる方は　railsチュートリアルをやってみましょう。