38
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Minitestでrailsのテストを書こう

Last updated at Posted at 2018-08-11

1 対象読者: テストって何?という人

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

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

2 準備しましょう

まずはちょいちょいっとテーブル用意
今回はユーザー一人につき、多数のブログを持つ1対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も編集してあげてあげましょう。

 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つのテストが走り、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 %> のブログ一覧
<% @user.blogs.each do |blog| %>
title: <%= blog.title %>
<%= link_to "本文を読む", blog_path(blog) %>
<% end %>
<%= link_to '新しく記事を書く', new_blog_url(id: @user.id) %>


views/blogs/new.html.erb

<% @blog.errors.full_messages.each do |message| %>


<%= message %>

<% 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のモデル数が1増える" 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

期待する振る舞いは、

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

の3つです。

ちなみに 「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


期待する振る舞いは、
**1、newページに飛ぶこと。**
**2、タイトルが入っていないのでテスト作成に失敗すること。**
**3、「Title can't be blank」というエラー文が表示されること。**
の3点です。
この状態で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チュートリアルをやってみましょう。





38
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?