280
217

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.

Rails チュートリアル 【初心者向け】 テストを10分でおさらいしよう! 

Last updated at Posted at 2018-09-07

Rails チュートリアルを勉強中のみなさま、こんにちは!

突然ですが、テストって、難しくないですか? 

第3章に突如として現れ、詳しい説明もなく、テストが始まり、

最後の14章までに、non stop でテストがたくさん出てきる・・・ 
 

テストが重要なのはわかったけど!
これって、初心者にはハードル高くないですか??? 

私は、何度となく挫折しかけました汗
この記事が、少しでもテストに対する抵抗感が減るきっかけになれば、幸いです。 

1. テストの種類について

Rails チュートリアルを進めていくと、
integration test っていうのが出てきます。

普通のテストとどう違うんだ!
使い分けがわからなくなりますよね。(自分だけでしょうか) 

 
テストは一般的に、3つに分かれます。

テスト名 概要
単体テスト モデルやビューヘルパー単体の動作をチェック
機能テスト コントローラー/ビューの呼び出し結果をチェック
統合テスト ユーザーの実際の操作を想定し、複数のコントローラーにまたがるアプリの挙動をチェックする

それぞれ、詳しくみていきましょう 
## 単体テスト

Rails で行うテストの中で、最も基本的なテスト。
アプリを構成するライブラリ(主にモデル)が、正しく動作するかをチェックします。 
 

Rails チュートリアル 第6章 リスト6.5

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 "should be valid" do
    assert @user.valid?
  end
end

assert メソッドは、第1引数がtrue である場合に、テストが成功したものとみなします。

setup メソッドで、テストが走る前に、インスタンス変数の @user を宣言し、valid?メソッドで有効性を確認しているわけですね。

assertメソッドにはそれ以外にも、
assert_not, assert_equal, assert_match などなど
数多くあるので、気になる方は、こちらをご参照ください。

##機能テスト
コントローラーの動作や、ビューの出力をチェックするためのテスト。
HTTPリクエストを擬似的に作成することで、アクションメソッドを実行し、HTTPステータスやテンプレート変数、最終的な出力の構造までを確認する。また、ルーティングもチェックします。

コントローラって、アプリが受け付けたWebリクエストを処理して 
レンダリングされたビューを返しますよね。 
 

機能テストでは、コントローラーのアクションが、リクエストや期待される結果(レスポンス、場合によってはHTMLビュー)をどう扱っているかをテストします。
つまり、以下のことを行うんです。

・Webリクエストが成功したか
・正しいページにリダイレクトされたか
・ユーザー認証が成功したか
・レスポンスのテンプレートに正しいオブジェクトが保存されたか
・ビューに表示されたメッセージは適切か

実際のコードを見てみましょう。

Rails チュートリアル第7章 リスト7.23 をご参照ください。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def create
    @user = User.new(user_params)
    if @user.save
    else
      render 'new'
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end
test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
  end
end

❶ get メソッドでリクエストを生成する。
まず、コントローラーを起動するために、getメソッドで、擬似的にHTTPリクエストを生成します。

get メソッド
get path, opts

path: リクエスト先のパス opts: 動作オプション (params, xhr, headersなど)

その他のHTTPメソッド(post, delete, patchなど)も、同じ構文となります。
このコードでは、引数 paramsを使用していますね。
params は、ハッシュ形式で、{キー: 値} と書きます。

❷ assertメソッド 
この機能テストでは、単体テストで使用できたassertメソッド に加え、次のような
assertメソッドを使用できます。 
 

メソッド 概要
assert_difference (exp [.diff [,msg]]){block} ブロック配下の処理を実行した前後で、式 expの値が引数 diffだけ変化しているか
assert_no_difference (exp [,msg]){block} ブロック配下の処理を実行した前後で式 expの値が変化しないか
assert_response (type [,msg]) 指定されたHTTPステータスが返されたか。:success(200)、:redirect(300番台)、:missing(404)、:error(500番台)など
assert_redirected_to ([opts [,msg]]) リダイレクト先 optsが正しいか
assert_template (temp [,msg]) 指定されたテンプレートが選択されたか
assert_select (selector [, equality [,msg]]) selectorに合致した要素の内容を引数equalityでチェック

Rails チュートリアルに、いっぱい出てきましたよね、これら・・・。 中でも、1つ個人的につまずいた、assert メソッドを抜粋します。
assert_select 'a[href=?]', about_path 

これは、about_path に合致するリンクが存在するかどうかを、確認しているものです。 この? が途中から、意味不明に見えてきたのですが、Railsチュートリアル リスト5.32に ちゃんと説明が書いてありました。   > Railsは、自動的にはてなマーク "?" を about_pathに置換しています。 これにより、次のようなHTMLがあるかどうかをチェックすることができます。 \...\

なるほど納得ですね〜 
 

統合テスト

これは、複数のコントローラーにまたがって、ユーザーの実際の操作を追跡する用途で利用するテスト。

早速実際のコードを見てみましょう。

Rails チュートリアル 第5章 リスト5.32

test/integration/site_layout_test.rb
require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
  end
end

このコードは、今までの知識だけで理解できますね! 
私がつまずいたのは、

follow redirect!

そんなに、力を込めて、redirect! するなよっていう気持ちでした.

Rails チュートリアル第8章 リスト8.23

test/integration/users_login_test.rb
require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end
  .
  .
  .
  test "login with valid information" do
    get login_path
    post login_path, params: { session: { email:    @user.email,
                                          password: 'password' } }
    assert_redirected_to @user
    follow_redirect!
    assert_template 'users/show'
    assert_select "a[href=?]", login_path, count: 0
    assert_select "a[href=?]", logout_path
    assert_select "a[href=?]", user_path(@user)
  end
end

これ
この follow redirect!

なんで必要か?

よく探したら、Rails チュートリアル第7章に書いてありました。

このメソッドは、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッドです。
 

あれ?これって、assert_redirected_to メソッドと
どう違うんだろうと思いませんか? 
 

おそらくですが 

assert _redirected_to は、駅員が、「お客さんこの駅へ向かう切符でよろしいですか?」 
と確認すること 
 
 
follow_redirect! は、 「その切符の行き先まで、実際に行くこと!」
の違いだと解釈しました。(違ってたら、コメントください。。)


なお、このテストの


assert_redirected_to @user


この書き方がよくわからない方。特に @user のとこ。
こちらの記事が最高にわかりやすかったので、初心者の方は、ぜひ読んでみてくださいね!
  

簡単にまとめますと、
redirect_to のあとは絶対パスが来る。
→ user_url(@user.id)
→ urlヘルパーと()は省略可能 → @user.id
→ モデルオブジェクト@user って書けば、Railsが自動的にid 探す
@userになる。


テストってかなり難しいと思います。
Railsチュートリアルを終わった今でも、かける自信はありません。
また、minitestの記事をググってもなかなか見つけることはできませんでした。 
 
この記事は、今後もバージョンアップして、少しでも皆様のお役に立てれればと思います。 
では、楽しいRails ライフを〜

参考文献:
Rails チュートリアル
Railsガイド
Ruby on Rails5 アプリケーションプログラミング

280
217
1

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
280
217

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?