Rails 3.1, RSpec: testing model validations

时光怂恿深爱的人放手 提交于 2019-12-02 16:20:31
Matthew

First I would like to say you have a wicked name.

Second, CONGRATULATIONS on you endeavor into TDD with ROR I promise once you get going you will not look back.

The simplest quick and dirty solution will be to generate a new valid model before each of your tests like this:

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

BUT what I suggest is you set up factories for all your models that will generate a valid model for you automatically and then you can muddle with individual attributes and see if your validation. I like to use FactoryGirl for this:

Basically once you get set up your test would look something like this:

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

Oh ya and here is a good railscast that explains it all better than me:

good luck :)


UPDATE: As of version 3.0 the syntax for factory girl has changed. I have amended my sample code to reflect this.

An easier way to test model validations (and a lot more of active-record) is to use a gem like shoulda or remarkable.

They will allow to the test as follows:

describe User

  it { should validate_presence_of :name }

end

Try this:

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

in new version rspec, you should use expect instead should, otherwise you'll get warning:

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

I have traditionally handled error content specs in feature or request specs. So, for instance, I have a similar spec which I'll condense below:

Feature Spec Example

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")

So then, I have my model spec testing whether something is valid, but then my feature spec which tests the exact output of the error message. FYI, these feature specs require Capybara which can be found here.

Like @nathanvda said, I would take advantage of Thoughtbot's Shoulda Matchers gem. With that rocking, you can write your test in the following manner as to test for presence, as well as any custom error message.

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

A little late to the party here, but if you don't want to add shoulda matchers, this should work with rspec-rails and 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!