「Everyday Rails - RSpecによるRailsテスト入門」を読んでいただき、どうもありがとうございます。
さっそく回答しようと思うのですが、すいません、僕はそもそも、載せていただいたテストコードに関してご質問の内容と直結しない部分が一番気になりました。
具体的には以下の3点です。
a@a
というのがまずありえないメールアドレスなので、正しいメールアドレスに見えない
it "ng1"
やit "ng2"
では第三者から見て、いったい何をテストしようとしているのかわからない
- もし「メールアドレスが不正ない場合」を検証したいのであれば、それ以外の項目(ここではパスワード)を正常にした方がテストの意図が伝わりやすい
というわけで、僕だったらこんなふうにテストを書きます。
(コメントは僕からの補足説明です)
ruby
1require 'rails_helper'
2
3RSpec.describe User, type: :model do
4 # itの説明を詳しく書く
5 it "全項目が正常なので検証エラーが起きない" do
6 # メールアドレスをある程度リアルなものにする
7 user = User.new(email: "alice@example.com", password: "111111", password_confirmation: "111111")
8 expect(user).to be_valid
9 end
10
11 it "メールアドレスが不正なので検証エラーになる" do
12 # メールアドレスだけ不正な状態にして、パスワードは正常にする
13 user = User.new(email: "alice@@example.com", password: "111111", password_confirmation: "111111")
14 user.valid?
15 expect(user.errors[:email]).to include("is invalid")
16 end
17
18 it "パスワードが未入力なので検証エラーになる" do
19 # パスワードだけ未入力にして、メールアドレスは正常にする
20 user = User.new(email: "alice@example.com")
21 user.valid?
22 expect(user.errors[:password]).to include("can't be blank")
23 end
24end
このようなテストであれば大きな問題はないと思います。
(各テストのuser
に関連があるかどうかは特に気になりません)
ちなみに、これは応用編になりますが、以下のようなポイントを押さえれば、よりRSpecらしいテストになります。
- 検証したい処理(ここではvalidation)をdescribeブロックで囲む
- 「もし〜の場合」に当たる部分をcontextで表現する
let
を活用して、重複を無くす
具体的にはこんな感じです。
ruby
1require 'rails_helper'
2
3RSpec.describe User, type: :model do
4 describe 'validation' do
5 let(:user) do
6 User.new(email: email, password: password, password_confirmation: password)
7 end
8
9 context '全項目が正常な場合' do
10 let(:email) { "alice@example.com" }
11 let(:password) { "111111" }
12 it "検証エラーが起きない" do
13 expect(user).to be_valid
14 end
15 end
16
17 context 'メールアドレスが不正な場合' do
18 let(:email) { "alice@@example.com" }
19 let(:password) { "111111" }
20 it "検証エラーになる" do
21 user.valid?
22 expect(user.errors[:email]).to include("is invalid")
23 end
24 end
25
26 context 'パスワードが未入力の場合' do
27 let(:email) { "alice@example.com" }
28 let(:password) { nil }
29 it "検証エラーになる" do
30 user.valid?
31 expect(user.errors[:password]).to include("can't be blank")
32 end
33 end
34 end
35end
contextやletといった構文の説明はすべてEveryday Railsの中で説明しているはずですので、本書を参照してください。
とはいえ、「RSpecらしさ」を追求すると沼にはまってしまうというか、「RSpecのいろんな機能を使いまくりたい!!」という変な欲求に駆られがちになるので、個人的には一つ前のコードでも十分じゃないかなーと思います。
以上のような回答で参考になるでしょうか?
もし解決していない疑問点があればコメントしてください。
追記
first_name以外の入力がなされていないことに不満を持っています
たしかにEveryday Railsのコード例はfirst_name: nil
以外の項目が未入力ですね。
それ以外の項目はちゃんと入力されていてfirst_name
だけが未入力、の方が「意図が伝わりやすい」という意味でベターです。
ですが、expect(user.errors[:first_name]).to_not include("can't be blank")
という形で「first_name
が未入力なら検証エラーになること」を担保できているので、テストの機能的には問題ない気がします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/03/21 13:13
2020/03/22 06:01