ChatGPT解决这个技术问题 Extra ChatGPT

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

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

有人有意见吗?


i
idmean

恭喜你努力进入 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

哦,这是a good railscast,它比我解释得更好:

祝你好运 :)

更新:从 version 3.0 开始,工厂女孩的语法发生了变化。我已经修改了我的示例代码以反映这一点。


非常感谢马修。有没有办法更接近我要测试的错误? X.should_not be_valid 对我来说似乎很笼统,谁知道以后的其他事情是否会使记录无效。然后,此测试将在错误的位置失败。顺便说一句,我想我将您的答案标记为已接受。我不是吗?
对,所以这就是为什么我主张工厂。您编写代码以在一个地方一次生成一个有效用户,然后编写一个测试以确保其在所有单个测试之前有效,以确保您可以使其无效。这样,如果由于某种原因您更改了模型,以便工厂不再产生有效用户,Factory.build(:user).should be_valid 测试将失败,您将知道您必须更新您的工厂...明白了吗? (是的,你接受了 my7 的回答)
@Feech FactoryGirl.build(:user, username: '').should have(1).errors_on(:username)
对我来说,关键是使用 build(或者如果您不使用 FactoryGirl,则使用 new)而不是 create。否则会在测试完成之前引发 ActiveRecord::RecordInvalid 异常,导致测试失败。
不要这样测试!请参阅nathanvda's answer below。如果您以这种方式进行测试,那么您实际上是在测试 ActiveRecord 的行为,该行为已经过测试。相反,使用 shoulda-matchers gem 来验证用户是否已进行验证。
n
nathanvda

测试模型验证(以及更多活动记录)的一种更简单的方法是使用像 shouldaremarkable 这样的 gem。

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

describe User

  it { should validate_presence_of :name }

end

这有助于检查您在模型中是否具有关联,但请注意,它实际上不会尝试创建没有名称的用户并检查其有效性
@brafales 实际上没有,afaik 这正是应该做的:它将尝试使用空白名称创建对象,并且应该给出错误。
W
Winston Kotzan

尝试这个:

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

这是我最喜欢的,很扎实,检查的是key而不是message,这是一个细节
您可以只使用 user = User.new(:username => "") 来避免命中 db
@TaufiqMuhammadi new 不会达到数据库级别验证,例如唯一性索引约束。
@mnort9 这个问题特别要求不必接触数据库
@TaufiqMuhammadi 很好,我错过了。不过对于那些寻求更完整的验证测试的人来说,值得注意的是
d
dayudodo

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

您还应该在示例名称中使用现在时动词而不是应该。以上可以改写为"has a valid factory""requires a username"
a
aceofbassgreg

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

功能规格示例

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,可在 here 中找到。


L
LaCroixed

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

m
marksiemers

在这里聚会有点晚了,但如果你不想添加应该匹配器,这应该与 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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅