Railsチュートリアルの7章まで進めましたが、テスト駆動型開発でテストをバリバリ記述していくのに悪戦苦闘してます。
使用されるテスト用のメソッドには特に詳しい説明もなく、いきなり出てくる感じになります。
assetとかassert_notとかとか・・・
これはMinitestとというRails標準のテストのためのフレームワークになります。
Minitestを使用することで、ルティング、各コントローラー間の処理、データーベースとのやり取り、メソッドの挙動やブラウザに返されるHTMLファイルの内容など、様々なものを簡単にテストすることができます。
聞くと便利そうですが、いざ使うとなるとスッと入ってこない箇所もあるので、今回はRailsチュートリアルにも出てくる、MInitestを使ったテストについてを解説していきます。
目次
テストの目的
テストの目的は以下の通りです。
- 機能が動作していることを保証する
- 機能に修正を加えた時に「これまで動作していた機能が動作しなくなる」というリスクを最小限に抑える
テストを書くという手間は発生してしまいますが、バグや大規模な変更へのリスクが減り、機能に修正を加えた後にいちいちブラウザで手動でテストを行う手間が大幅に削減できます。
テストのフォルダ構成
テスト関連のフォルダは「rails new」を実行した時に「/test」に作成されます。
「/test」の構成は以下の通りです。
controllers | コントローラ・ビュー・ルーティングをまとめたテストを保存するフォルダ |
---|---|
fixtures | テストデータ生成用のファイルを保存するフォルダ |
helpers | ビューヘルパーのテストを保存するフォルダ |
integration | 複数のコントローラをまたいだテストを保存するフォルダ(統合テスト) |
mailers | メーラーのテストを保存するフォルダ |
models | モデルのテストを保存するフォルダ |
system | システムテスト(Javascriptなど)を保存するフォルダ |
application_system_test_case.rb | システムテストのデフォルト設定を記述するファイル |
test_helper.rb | テストのデフォルト設定を記述するファイル |
テストファイルの作成方法
テスト用のファイルは、コントローラー作成時などに自動生成されるものと、専用のコマンドを実行して作成するものがあります。
controller | コントローラー作成時に動生成 |
---|---|
model、fixture | モデル作成時に自動生成。 |
mailer | メーラー作成時に自動生成 |
integration | 「$ g integration_test ファイル名」で作成 |
基本的な文法
基本的な文法は以下のようになります。
1 2 3 4 5 6 7 |
require "test_helper" class SampleTest < ActiveSupport::TestCace test "the truth" do assert true end end |
まず、「require ‘test_helper’によって、test/test_helper.rbに記載されているデフォルト設定が読み込まれます。
全てのテストファイルに「require ‘test_helper’」は組み込まれるので、このファイルに追加したメソッドはテスト全体で使用することができます。
上記の「SampleTest」クラスは「ActiveSuppoort::TestCase」クラスを継承しておりい、「ActiveSupport::TestCase」クラスのスーパークラスはRuby標準のテスティングフレームワークである「Minitest::Test」クラスになります。
そのため、「Minitest::Test」のアサーションメソッドは全て利用することができます。
ちなみに「Minitest::Test」クラスの場合は以下のように、メソッド名に「test_」とついたものをテスト実行時にランダムに実行していくことになります。
1 2 3 4 5 6 7 8 9 |
class SampleTest < Minitest::Test def test_sample ... end def test_user ... end end |
しかし、Railsの場合、もっと読みやすいテスト名にすることができます。
1 2 3 4 5 6 7 |
require 'test_helper' class ArticleTest < ActiveSupport::TestCase test "the sample" do assert true end end |
testメソッドは引数に文字列とブロックを受け付けます。
「test “the sample”と記述することで、行頭にtestを追加し、スペースをアンダーバーに変更してくれます。
(上記の例だと、「test_the_sample」メソッドとなる)
testメソッドを使用することで、テストの命名に気を使わなくても済み、実際のテストコードはブロックに記述することになります。
このように記載したテストは以下のコマンドで実行できます。
1 |
$ rails test |
「test」の部分は「t」と省略可能です。
setup/teardownメソッド
テスト実行前に毎回実行してほしい処理があれば、setupメソッドが使用できます。
1 2 3 4 5 |
class StaticPagesControllerTest < ActionDispatch::IntegrationTest def setup @base_title = "Ruby on Rails Tutorial Sample App" end ・・・ |
Ruby標準のMiniTestでは上記のように「def setup」と書いていましたが、以下のように「setup do」と分かりやすい記法を使用することができます。
1 2 3 4 5 |
class StaticPagesControllerTest < ActionDispatch::IntegrationTest setup do @base_title = "Ruby on Rails Tutorial Sample App" end ・・・ |
setupメソッドとは反対に、テスト実行後に行いたい処理があれば、teardownメソッドが使用できます。
1 2 3 4 5 |
class StaticPagesControllerTest < ActionDispatch::IntegrationTest teardown do @base_title = "Ruby on Rails Tutorial Sample App" end ・・・ |
setupやteardownメソッドはデータベースから決まった値を取得しておいたりなんかに使用できますね。
テスト(アサーション)のメソッド
アサーションとはRuby標準のMinitestで用意されている、テスト用のメソッドになります。
Railsチュートリアルでは不意にassert、assert_noとかが出てきて混乱しますが、これらは全てアサーションと呼ばれるメソッドになります。
代表的な例を下記していきます。
assert
testが真(nil、false以外)の場合にテストが成功します。
1 |
assert @user.valid? |
assert_not
testが偽の場合にテスト成功します。
1 |
assert_not flash.empty? |
assert_nil
オブジェクト.empty?が真の場合にテストが成功します。
1 |
assert_nil current_user |
assert_empty
オブジェクト.empty?が真の場合にテストが成功します。
1 |
assert_empty cookies['remember_token'] |
assert_not_empty
オブジェクト.empty?が偽の場合にテストが成功します。
1 |
assert_not_empty cookies['remember_token'] |
assert_equal
第1引数 == 第2引数が真の場合にテストが成功します。
1 |
assert_equal @user, current_user |
assert_not_equal
第1引数 == 第2引数が偽の場合にテストが成功します。
1 |
assert_not_equal @user.reset_digest, @user.reload.reset_digest |
assert_redirected_to
適切にリダイレクトされている場合にテストが成功します。
1 2 |
post login_url assert_redirected_to login_url |
assert_response
レスポンスが指定したステータスコードになっている場合にテストが成功します。
1 2 |
get root_path assert_response :success |
assert_select
指定した種類、個数のHTML要素が存在する場合にテストが成功します。
1 |
assert_select 'div#error_explanation' |
assert_match
指定した正規表現に一致する場合にテストが成功します。
1 |
assert_match @user.followers.count.to_s, response.body |
assert_difference
create/update/delete実行後のレコード数が指定通りに変化している場合にテストが成功します。
1 2 3 4 5 |
assert_difference '@user.following.count', 1 do post relationships_path, params:{ followed_id: @other.id } end |
assert_no_difference
create/update/delete実行後のレコード数が指定通りに変化していない場合にテストが成功します。
1 2 3 4 5 |
assert_no_difference '@user.following.count', 1 do post relationships_path, params:{ followed_id: @other.id } end |
まとめ
Railsのテストについてまとめてみましたが、いかかがだったでしょうか?
Railsチュートリアルでは不意にテストが出てくる且つテスト駆動型開発なので、まずテストを書いて行くことになるので、Rails初めてというかテストを書くといった習慣がない人はかなり戸惑うのではないかと思います。
今回紹介したテストメソッド(アサーション)は良く出てくる(Railsチュートリアルにも出てくる)ものに絞ってまとめています。
テストメソッドには他にも指定した例外が発生するかをテストするようなメソッドなど色々とあるので、新しいものに触れる度に加筆していきたいと思います。
テストをきちんと理解し、テスト駆動型開発を行うことで修正に強いプログラムが組めるようになっていきましょう。
Railsの中で使用されるRubyの本になります。
Railsチュートリアルをやる前にRubyはProgateなどで学習している方も多いかと思いますが、Progateからさらに発展したRubyの入門書になります。
RailsはRubyで記載するとはいえ、Rubyの文法にはあまり触れられないので、Railsチュートリアルを受けるための相棒としてオススメです。