コジマです。
【Rails#11】モデルのテストデータ作ろうぜ【Fixture】
の続きです。
思ったより長くなってしまったんですよね。
対象読者は前回と同じ
<
h1>対象読者
Progate終わったけどテストの方法も覚えたい、って人
Railsでテスト作る時どう考えりゃいいんだ?って人
Fixtureやminitest復習したい人
この記事でやること
今回は
- モデルの単体テストの実装
- バグ潰し(モデルのバリデーション定義)
をしていきたいと思います。
予めお断りしておきたいのですが、
独学なのでこれで動くテストはできても正しい実装になっているかはわからないです。
申し訳ないです。
方針
方針としては
ユーザーデータに特定の値をセットし、user.valid実行時の戻り値を見る
trueであってほしいもの(正常系)はassert
falseであってほしいもの(異常系)はassert_notで判定していこうかと思います。
テストを作る
user_test.rbは上記の方針でこうなりました。
require 'test_helper' class UserTest < ActiveSupport::TestCase def setup @user = User.new( login_id: "hoge", display_name: "hoge", password:"hogehoge", password_confirmation: "hogehoge", email: "hoge@email.com", authority_flag: "0" ) end #login_id(異常系) #重複する2ユーザー test "check login_id is duplicate invalid" do @user.login_id = "test" assert_not @user.valid?,"login_id can't duplicated" end #記号を含む test "check login_id include symbol invalid" do @user.login_id = "test@" assert_not @user.valid?,"login_id can't include symbols" end #全角文字を含む test "check login_id include wide charactor invalid" do @user.login_id = "テスト" assert_not @user.valid?,"login_id can't include wide charactors" end #nil test "check login_id is nil invalid" do @user.login_id = "" assert_not @user.valid?,"login_id is not nil" end #3文字 test "check login_id is too short invalid" do @user.login_id = "foo" assert_not @user.valid?,"login_id is more than 4 charactors" end #21文字 test "check login_id is too long invalid" do @user.login_id = "abcdeabcdeabcdeabcdea" assert_not @user.valid?,"login_id is less than 20 charactors" end #display_name(異常系) #nil test "check display_name is nil invalid" do @user.display_name = "" assert_not @user.valid?,"display_name is not nil" end #21文字 test "check display_name is too long invalid" do @user.display_name = "21文字の名前の長いユーザー名にしています" assert_not @user.valid?,"display_name is less than 20 charactors" end #password(正常系) #記号を含む test "check password include symbol invalid" do @user.password = "test/" @user.password_confirmation = "test/" assert_not @user.valid?,"password can't include symbols" end #全角文字を含む test "check password include wide charactor invalid" do @user.password = "パスワード" @user.password_confirmation = "パスワード" assert_not @user.valid?,"password can't include wide charactors" end #nil test "check password is nil invalid" do @user.password = "" @user.password_confirmation = "" assert_not @user.valid?,"password is not nil" end #3文字 test "check password is too short invalid" do @user.password = "foo" @user.password_confirmation = "foo" assert_not @user.valid?,"password is more than 4 charactors" end #21文字 test "check password is too long invalid" do @user.password = "testtesttesttesttesta" @user.password_confirmation = "testtesttesttesttesta" assert_not @user.valid?,"password is less than 20 charactors" end #email(異常系) #重複する2ユーザー test "check email duplicate invalid" do @user.email = "test@email.com" assert_not @user.valid?,"email must be unique" end #@がない test "check email not include @ invalid" do @user.email = "test.com" assert_not @user.valid?,"email must be mail format" end #全角文字含む test "check email include wide characters invalid" do @user.email = "テスト@test.com" assert_not @user.valid?,"email can't include wide characters" end #nil test "check email is nil invalid" do @user.email = "" assert_not @user.valid?,"email is not nil" end #authority_flag(異常系) #nil test "check authority_flag is nil invalid" do @user.authority_flag = "" assert_not @user.valid?,"authority_flag is not nil" end #2 test "check authority_flag is other number of 0 or 1 invalid" do @user.authority_flag = "2" assert_not @user.valid?,"authority_flag must be 0 or 1" end #全然関係ない文字 test "check authority_flag has nothing to do with number invalid" do @user.authority_flag = "A" assert_not @user.valid?,"authority_flag must be 0 or 1" end #正常系 #login_id 4文字、display_name 1文字 password 4文字 #明示的に再宣言 test "check minimum length valid" do @user.login_id = "hoge" @user.display_name = "hoge" @user.password = "hoge" @user.password_confirmation = "hoge" assert @user.save,"check minimum length" end #login_id 4文字、display_name 1文字 #password 4文字 authority_flag 1 test "check admin user valid" do @user.login_id = "hogehogeho" @user.display_name = "管理者" @user.password = "hogehogeho" @user.password_confirmation = "hogehogeho" @user.authority_flag = "1" assert @user.save,"check admin" end #login_id 20文字、display_name 20文字 password 20文字 test "check max length valid" do @user.login_id = "abcdeabcdeabcdeabcde" @user.display_name = "abcdeabcdeabcdeabcde" @user.password = "abcdeabcdeabcdeabcde" @user.password_confirmation = "abcdeabcdeabcdeabcde" assert @user.save,"check minimum length" end end
すっごい長いですが、単体試験はこんなもんかと。
minitest-reportersの設定
test_helperを編集して以下のようにします。
ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' require "minitest/reporters" Minitest::Reporters.use! class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests # in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... end
使い方はRailsチュートリアルにも書いていますが。
公式のgithubにも書いています。
テストを実行
今回テストするのはユーザーモデルだけに絞るのでこんな感じでコマンド実行
$ rails test test/models/user_test.rb
minitest-reportersを導入するとこうしてカラーで出てきます。
とても見やすくなります。
全文はこんな感じ
$ rails test test/models/user_test.rb Running via Spring preloader in process 13071 Started with run options --seed 3259 FAIL["test_check_login_id_is_nil_invalid", Minitest::Result, 0.058835628999077016] test_check_login_id_is_nil_invalid#Minitest::Result (0.06s) login_id is not nil test/models/user_test.rb:37:in `block in <class:UserTest>' FAIL["test_check_login_id_is_too_short_invalid", Minitest::Result, 0.07730235399867524] test_check_login_id_is_too_short_invalid#Minitest::Result (0.08s) login_id is more than 4 charactors test/models/user_test.rb:43:in `block in <class:UserTest>' FAIL["test_check_display_name_is_too_long_invalid", Minitest::Result, 0.10149881400138838] test_check_display_name_is_too_long_invalid#Minitest::Result (0.10s) display_name is less than 20 charactors test/models/user_test.rb:62:in `block in <class:UserTest>' FAIL["test_check_password_include_wide_charactor_invalid", Minitest::Result, 0.1173242949989799] test_check_password_include_wide_charactor_invalid#Minitest::Result (0.12s) password can't include wide charactors test/models/user_test.rb:76:in `block in <class:UserTest>' FAIL["test_check_authority_flag_is_nil_invalid", Minitest::Result, 0.12005681099981302] test_check_authority_flag_is_nil_invalid#Minitest::Result (0.12s) authority_flag is not nil test/models/user_test.rb:123:in `block in <class:UserTest>' FAIL["test_check_password_include_symbol_invalid", Minitest::Result, 0.1337837649989524] test_check_password_include_symbol_invalid#Minitest::Result (0.13s) password can't include symbols test/models/user_test.rb:70:in `block in <class:UserTest>' FAIL["test_check_display_name_is_nil_invalid", Minitest::Result, 0.14728031599952374] test_check_display_name_is_nil_invalid#Minitest::Result (0.15s) display_name is not nil test/models/user_test.rb:56:in `block in <class:UserTest>' FAIL["test_check_email_not_include_@_invalid", Minitest::Result, 0.17270141500193859] test_check_email_not_include_@_invalid#Minitest::Result (0.17s) email must be mail format test/models/user_test.rb:106:in `block in <class:UserTest>' FAIL["test_check_password_is_too_long_invalid", Minitest::Result, 0.18367412500083447] test_check_password_is_too_long_invalid#Minitest::Result (0.18s) password is less than 20 charactors test/models/user_test.rb:94:in `block in <class:UserTest>' FAIL["test_check_login_id_include_wide_charactor_invalid", Minitest::Result, 0.19625735500085284] test_check_login_id_include_wide_charactor_invalid#Minitest::Result (0.20s) login_id can't include wide charactors test/models/user_test.rb:31:in `block in <class:UserTest>' FAIL["test_check_email_is_nil_invalid", Minitest::Result, 0.2088199159989017] test_check_email_is_nil_invalid#Minitest::Result (0.21s) email is not nil test/models/user_test.rb:116:in `block in <class:UserTest>' FAIL["test_check_email_include_wide_characters_invalid", Minitest::Result, 0.22340923600131646] test_check_email_include_wide_characters_invalid#Minitest::Result (0.22s) email can't include wide characters test/models/user_test.rb:111:in `block in <class:UserTest>' FAIL["test_check_login_id_is_too_long_invalid", Minitest::Result, 0.23724529500032077] test_check_login_id_is_too_long_invalid#Minitest::Result (0.24s) login_id is less than 20 charactors test/models/user_test.rb:49:in `block in <class:UserTest>' FAIL["test_check_password_is_too_short_invalid", Minitest::Result, 0.25036597100188374] test_check_password_is_too_short_invalid#Minitest::Result (0.25s) password is more than 4 charactors test/models/user_test.rb:88:in `block in <class:UserTest>' FAIL["test_check_authority_flag_has_nothing_to_do_with_number_invalid", Minitest::Result, 0.26820372699876316] test_check_authority_flag_has_nothing_to_do_with_number_invalid#Minitest::Result (0.27s) authority_flag must be 0 or 1 test/models/user_test.rb:133:in `block in <class:UserTest>' FAIL["test_check_authority_flag_is_other_number_of_0_or_1_invalid", Minitest::Result, 0.27078463100042427] test_check_authority_flag_is_other_number_of_0_or_1_invalid#Minitest::Result (0.27s) authority_flag must be 0 or 1 test/models/user_test.rb:128:in `block in <class:UserTest>' FAIL["test_check_login_id_is_duplicate_invalid", Minitest::Result, 0.2827955819993804] test_check_login_id_is_duplicate_invalid#Minitest::Result (0.28s) login_id can't duplicated test/models/user_test.rb:19:in `block in <class:UserTest>' FAIL["test_check_email_duplicate_invalid", Minitest::Result, 0.29472553500090726] test_check_email_duplicate_invalid#Minitest::Result (0.29s) email must be unique test/models/user_test.rb:101:in `block in <class:UserTest>' FAIL["test_check_login_id_include_symbol_invalid", Minitest::Result, 0.30534323699976085] test_check_login_id_include_symbol_invalid#Minitest::Result (0.31s) login_id can't include symbols test/models/user_test.rb:25:in `block in <class:UserTest>' 23/23: [================================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.30617s 23 tests, 23 assertions, 19 failures, 0 errors, 0 skips
login_id:6項目
password:5項目
display_name:2項目
email:4項目
authority_flag:3項目
正常系:3項目
計23項目
で、正常系3項目、パスワードのnilチェック以外はまだ試験に失敗した状態です。
残り19項目の試験を通るようにモデルを定義していきます。
モデルを定義する
class User < ApplicationRecord has_secure_password end
bcryptを使用するためにhas_secure_passwordだけは書いてました。
他の定義もしていきます。
class User < ApplicationRecord VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i VALID_HALF_CHARACTER_REGEX = /\A[a-zA-Z0-9]+\z/i has_secure_password validates :login_id, presence: true, uniqueness: true, length: { maximum: 20,minimum: 4}, format: { with: VALID_HALF_CHARACTER_REGEX } validates :display_name, presence: true, length: { maximum: 20} validates :password, presence: true, length: { maximum: 20,minimum: 4}, format: { with: VALID_HALF_CHARACTER_REGEX } validates :email, presence: true, uniqueness: true, format: { with: VALID_EMAIL_REGEX } validates :authority_flag, presence: true validates_inclusion_of :authority_flag, in: %w( 0 1 ) end
前回の記事で書いた仕様に沿ってモデルを定義しました。
いざ、尋常に
テストを実行する。これで
$ rails test test/models/user_test.rb
できました!
あぁ、よかった。
本日スタテクさんのもくもく会に行っていたのですが、
authority_flagの設計がよろしくないというレビューを受けたので、
次回はカラムの定義の変更、前回と今回の記事の補足など書いていきたいと思います。
以上、コジマでした。