web-dev-qa-db-ja.com

Rails 3.1、RSpec:モデル検証のテスト

私はRailsでTDDから旅を始めましたが、解決策が見つからないモデル検証のテストに関する小さな問題に遭遇しました。ユーザーモデルがあるとします。

class User < ActiveRecord::Base
  validates :username, :presence => true
end

そして簡単なテスト

it "should require a username" do
  User.new(:username => "").should_not be_valid
end

これはプレゼンス検証を正しくテストしますが、より具体的にしたい場合はどうすればよいですか?たとえば、エラーオブジェクトでfull_messagesをテストします。

it "should require a username" do
  user = User.create(:username => "")
  user.errors[:username].should ~= /can't be blank/
end

最初の試み(should_not be_validを使用)に関する私の懸念は、RSpecが説明的なエラーメッセージを生成しないことです。それは単に「有効であると思われますか?ただし、2番目のテスト例には小さな欠点があります。エラーオブジェクトを取得するために、新しいメソッドの代わりにcreateメソッドを使用します。

私は自分のテストでテスト対象をより具体的にしたいのですが、同時にデータベースに触れる必要はありません。

誰にも入力がありますか?

69
Feech

最初に、あなたは邪悪な名前を持っていると言いたいです。

第二に、RORを使用してTDDに取り組んでいるおめでとうございます。

最も簡単で迅速な解決策は、次のような各テストの前に新しい有効なモデルを生成することです。

 before(:each) do
    @user = User.new
    @user.username = "a valid username"
 end

しかし、私が提案するのは、有効なモデルを自動的に生成するすべてのモデルのファクトリーを設定し、個々の属性を調整して検証を確認することです。このために FactoryGirl を使用したい:

基本的に、設定するとテストは次のようになります。

it "should have valid factory" do
    FactoryGirl.build(:user).should be_valid
end

it "should require a username" do
    FactoryGirl.build(:user, :username => "").should_not be_valid
end

ああ、これは 良いrailscast です。

幸運を :)


更新: バージョン3. の時点で、ファクトリーガールの構文が変更されました。これを反映するためにサンプルコードを修正しました。

96
Matthew

モデル検証(およびより多くのアクティブレコード)をテストする簡単な方法は、 shoulda または remarkable のようなgemを使用することです。

次のようにテストを許可します。

describe User

  it { should validate_presence_of :name }

end
43
nathanvda

これを試して:

it "should require a username" do
  user = User.create(:username => "")
  user.valid?
  user.errors.should have_key(:username)
end
16
Winston Kotzan

新しいバージョンのrspecでは、代わりにexpectを使用する必要があります。そうしないと、警告が表示されます。

it "should have valid factory" do
    expect(FactoryGirl.build(:user)).to be_valid
end

it "should require a username" do
    expect(FactoryGirl.build(:user, :username => "")).not_to be_valid
end
4
dayudodo

従来、機能またはリクエストの仕様でエラーコンテンツの仕様を処理していました。したがって、たとえば、以下に要約する類似の仕様があります。

機能仕様例

before(:each) { visit_order_path }

scenario 'with invalid (empty) description' , :js => :true do

  add_empty_task                                 #this line is defined in my spec_helper

  expect(page).to have_content("can't be blank")

そのため、何かが有効かどうかをテストするモデル仕様がありますが、エラーメッセージの正確な出力をテストする機能仕様があります。参考までに、これらの機能仕様には here で見つかるCapybaraが必要です。

0
aceofbassgreg

@nathanvdaが言ったように、Thoughtbotの Shoulda Matchers gemを利用します。ロッキングを使用すると、プレゼンスとカスタムエラーメッセージをテストするために、次の方法でテストを作成できます。

RSpec.describe User do

  describe 'User validations' do
    let(:message) { "I pitty da foo who dont enter a name" }

    it 'validates presence and message' do
     is_expected.to validate_presence_of(:name).
      with_message message
    end

    # shorthand syntax:
    it { is_expected.to validate_presence_of(:name).with_message message }
  end

end
0
LaCroixed

ここでのパーティーに少し遅れましたが、shouldaマッチャーを追加したくない場合、これはrspec-Railsとfactorybotで動作するはずです。

# ./spec/factories/user.rb
FactoryBot.define do
  factory :user do
    sequence(:username) { |n| "user_#{n}" }
  end
end

# ./spec/models/user_spec.rb
describe User, type: :model do
  context 'without a username' do
    let(:user) { create :user, username: nil }

    it "should NOT be valid with a username error" do
      expect(user).not_to be_valid
      expect(user.errors).to have_key(:username)
    end
  end
end
0
marksiemers