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

This correctly tests the presence validation, but what if I want to be more specific? For example, testing full_messages on the errors object..

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

我对初始尝试(使用 should _ not be _ valid)的担心是 RSpec 不会产生描述性错误消息。它只是说“期望有效?”?返回虚假,得到真实。”但是,第二个测试示例有一个小缺点: 它使用 create 方法而不是 new 方法来获取错误对象。

我希望我的测试能够更具体地说明它们在测试什么,但同时又不必触及数据库。

有人有什么想法吗?

61871 次浏览

祝贺你努力进入 TDD 与 ROR 我保证,一旦你走了,你不会回头看。

最简单快捷的解决方案是在每个测试之前生成一个新的有效模型,如下所示:

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

但我的建议是,为所有模型建立工厂,这将自动为您生成一个有效的模型,然后您可以混淆个别属性,看看您的验证。我喜欢使用 工厂女孩:

基本上,一旦你设置好你的测试就会像这样:

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

哦,是的,这是 好的铁路广播,它比我更好地解释了这一切:

祝你好运


更新: 从 版本3.0开始,工厂女工的语法已经改变了。我已经修改了我的样本代码来反映这一点。

测试模型验证(以及更多的活动记录)的一种更简单的方法是使用像 应该的太不可思议了这样的 gem。

它们将允许进行以下测试:

describe User


it { should validate_presence_of :name }


end

我一直在处理特性或请求规格中的错误内容规格。所以,举个例子,我有一个类似的规格,我将在下面简述:

特性规格示例

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

然后,我有我的模型规范来测试某些东西是否有效,然后我的特性规范来测试错误消息的确切输出。仅供参考,这些功能规格需要水豚,可以找到 给你

试试这个:

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

在 new version rspec 中,应该使用 Expal 而不是 should,否则会收到警告:

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

就像@nathanvda 说的,我会利用 Thoughtbot 的 应该是火柴宝石。通过这种摇晃,您可以按照以下方式编写测试,以测试是否存在,以及任何自定义错误消息。

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

现在说这个有点晚了,但是如果你不想添加 should da 匹配器,这个应该可以用于 rspec-ails 和 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