Ruby-on-rails Rails 3.1、RSpec:测试模型验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7537112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails 3.1, RSpec: testing model validations
提问by Feech
I have started my journey with TDD in Rails and have run into a small issue regarding tests for model validations that I can't seem to find a solution to. Let's say I have a User model,
我在 Rails 中开始了 TDD 之旅,但遇到了一个关于模型验证测试的小问题,我似乎无法找到解决方案。假设我有一个 User 模型,
class User < ActiveRecord::Base
validates :username, :presence => true
end
and a simple test
和一个简单的测试
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..
这正确地测试了存在验证,但是如果我想更具体怎么办?例如,在错误对象上测试 full_messages..
it "should require a username" do
user = User.create(:username => "")
user.errors[:username].should ~= /can't be blank/
end
My concern about the initial attempt (using should_not be_valid) is that RSpec won't produce a descriptive error message. It simply says "expected valid? to return false, got true." However, the second test example has a minor drawback: it uses the create method instead of the new method in order to get at the errors object.
我对最初尝试(使用 should_not be_valid)的担忧是 RSpec 不会产生描述性错误消息。它只是说“预期有效?返回假,得到真。” 但是,第二个测试示例有一个小缺点:它使用 create 方法而不是 new 方法来获取错误对象。
I would like my tests to be more specific about what they're testing, but at the same time not have to touch a database.
我希望我的测试更具体地说明他们正在测试的内容,但同时不必接触数据库。
Anyone have any input?
有人有任何意见吗?
回答by 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.
其次,祝贺您通过 ROR 努力进入 TDD,我保证一旦您开始,您将不会回头。
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 FactoryGirlfor this:
但是我建议您为所有模型设置工厂,这些工厂将自动为您生成有效模型,然后您可以混淆各个属性并查看您的验证。我喜欢为此使用FactoryGirl:
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 railscastthat explains it all better than me:
哦,是的,这是一个很好的 Railscast,它比我更好地解释了这一切:
good luck :)
祝你好运 :)
UPDATE: As of version 3.0the syntax for factory girl has changed. I have amended my sample code to reflect this.
更新:从3.0 版开始,工厂女孩的语法发生了变化。我已经修改了我的示例代码以反映这一点。
回答by nathanvda
An easier way to test model validations (and a lot more of active-record) is to use a gem like shouldaor remarkable.
测试模型验证(以及更多活动记录)的一种更简单的方法是使用像shoulda或非凡的 gem 。
They will allow to the test as follows:
他们将允许进行如下测试:
describe User
it { should validate_presence_of :name }
end
回答by Winston Kotzan
Try this:
尝试这个:
it "should require a username" do
user = User.create(:username => "")
user.valid?
user.errors.should have_key(:username)
end
回答by dayudodo
in new version rspec, you should use expect instead should, otherwise you'll get warning:
在新版本的 rspec 中,您应该使用 expect 代替 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
回答by LaCroixed
Like @nathanvda said, I would take advantage of Thoughtbot's Shoulda Matchersgem. With that rocking, you can write your test in the following manner as to test for presence, as well as any custom error message.
就像@nathanvda 所说的那样,我会利用 Thoughtbot 的ShouldaMatchers宝石。通过这种摇摆,您可以按以下方式编写测试以测试是否存在以及任何自定义错误消息。
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
回答by marksiemers
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:
这里的聚会有点晚了,但如果你不想添加 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
回答by aceofbassgreg
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.
那么,我让我的模型规范测试某些内容是否有效,然后我的功能规范测试错误消息的确切输出。仅供参考,这些功能规范需要 Capybara,可在此处找到。

