Rails 3.1,RSpec:测试模型验证

发布于 2024-12-06 09:43:45 字数 730 浏览 2 评论 0原文

我已经开始了 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 不会生成描述性错误消息。它只是说“预期有效?返回 false,得到 true”。然而,第二个测试示例有一个小缺点:它使用 create 方法而不是 new 方法来获取错误对象。

我希望我的测试能够更具体地说明他们正在测试的内容,但同时不必接触数据库。

有人有任何意见吗?

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,

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..

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.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

月下伊人醉 2024-12-13 09:43:45

恭喜您通过 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.0< /a> 工厂女孩的语法已更改。我修改了示例代码以反映这一点。

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

Here is a good railscast that explains it all better than me:


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

故事灯 2024-12-13 09:43:45

测试模型验证(以及更多活动记录)的一种更简单的方法是使用像 shoulda卓越

他们将允许进行如下测试:

describe User

  it { should validate_presence_of :name }

end

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
2024-12-13 09:43:45

试试这个:

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

Try this:

it "should require a username" do
  user = User.create(:username => "")
  user.valid?
  user.errors.should have_key(:username)
end
空心空情空意 2024-12-13 09:43:45

在新版本的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

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
关于从前 2024-12-13 09:43:45

我传统上是在功能或请求规范中处理错误内容规范。因此,举例来说,我有一个类似的规范,我将在下面对其进行浓缩:

功能规范示例

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

然后,我让我的模型规范测试某些内容是否有效,然后我的功能规范测试确切的错误消息的输出。仅供参考,这些功能规范需要 Capybara,可以在此处找到。

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.

掩于岁月 2024-12-13 09:43:45

就像 @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

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
平安喜乐 2024-12-13 09:43:45

有点晚了,但如果你不想添加 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文