1. はじめに
現在、RailsチュートリアルでRuby on Railsを学習しています。
第6章で紹介されるテストコードに対してRubocopで解析をかけたところ、assert @user.valid?
ではなくassert_predicate(@user, :valid?)
の使用を推奨されました。
今回はこれら2つの違いについてまとめていきます。
2. assert・assert_predicateとは
assertメソッドもassert_predicateメソッドもMinitestで使えるアサーションの1つです。
Rails テスティングガイドの説明を引用してまとめると以下の通りです。
■ assert
指定した式(test)がtrueである場合、テスト成功。
assert( test, [msg] )
test
はtrueであると主張する。
■ asset_predicate
オブジェクト(obj)の述語メソッド(predicate)の結果がtrueである場合、テスト成功。
assert_predicate ( obj, predicate, [msg] )
obj.predicate
はtrueであると主張する (例:assert_predicate str, :empty?
)。
assert_predicate(@user, :valid?)
は@user.valid?
がtrueの場合に成功とも言い換えることができます。そのため、assert @user.valid?
とassert_predicate(@user, :valid?)
は同じ内容をテストしていると言えます。
3. assert・assert_predicateの比較
次に、テストコードを実際に実行させ、それぞれのアサーションで出力結果にどのような違いがあるのかを比較していきます。
3.1 実行内容
name属性が空白の場合にエラーとなるバリデーションを設定し、実行結果を比較します。
class User < ApplicationRecord
validates :name, presence: true
end
3.2 実行結果(成功)
作成するインスタンスのname属性に対し、"Example User”を与えテストを成功させます。
require "test_helper"
class UserTest < ActiveSupport::TestCase
# name属性に"Example User"を与え、テストを成功させる。
def setup
@user = User.new(name: "Example User", email: "user@example.com")
end
test "should be vaild with assert" do
assert @user.valid?
end
test "should be vaild with assert predicate" do
assert_predicate(@user, :valid?)
end
end
rails test test/models/user_test.rb
の実行結果です。
$ rails test test/models/user_test.rb
Running 2 tests in a single process (parallelization threshold is 50)
Started with run options --seed 9459
2/2: [=================================] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.05677s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
想定通り、どちらのテストも成功し上記の出力結果が得られました。
3.3 実行結果(失敗)
作成するインスタンスのname属性に対し、空白を与えテストを失敗させます。
require "test_helper"
class UserTest < ActiveSupport::TestCase
# name属性に空白を与え、テストを失敗させる。
def setup
@user = User.new(name: " ", email: "user@example.com")
end
test "should be vaild with assert" do
assert @user.valid?
end
test "should be vaild with assert predicate" do
assert_predicate(@user, :valid?)
end
end
rails test test/models/user_test.rb
の実行結果です。
$ rails test test/models/user_test.rb
Running 2 tests in a single process (parallelization threshold is 50)
Started with run options --seed 40102
FAIL UserTest#test_should_be_vaild_with_assert_predicate (0.10s)
Expected #<User id: nil, name: " ", email: "user@example.com", created_at: nil, updated_at: nil> to be valid?.
test/models/user_test.rb:13:in `block in <class:UserTest>'
FAIL UserTest#test_should_be_vaild_with_assert (0.10s)
Expected false to be truthy.
test/models/user_test.rb:9:in `block in <class:UserTest>'
2/2: [================] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.10406s
2 tests, 2 assertions, 2 failures, 0 errors, 0 skips
想定通りどちらのテストも失敗となりましたが、異なるエラーメッセージが表示されました。エラーメッセージの箇所を抜粋すると、以下の通りです。
■ assert
Expected false to be truthy.
■ assert_predicate
Expected #<User id: nil, name: " ", email: "user@example.com", created_at: nil, updated_at: nil> to be valid?.
assertの場合、trueを期待しているのに対し、falseであるという決められたエラーメッセージが出力される。
assert_predicateの場合、指定したオブジェクトの属性情報と、to be valid?
のようにテスト内容(述語メソッド)が出力される。
4. まとめ
assert_predicateメソッドの方が、テストが失敗したときにより具体的なエラーメッセージが提供されるため、何が間違っていたのかを理解しやすくなると感じました。
テスト結果は変わらないため、個人の好みやチームのコーディングルールによって決めるぐらいで良いかと思います。