使用RSpec测试Rails模型验证,而不测试AR本身

时间:2016-05-21 16:08:24

标签: ruby-on-rails ruby unit-testing testing rspec

使用RSpec测试Rails模型验证,而不测试AR本身

让我们设置模型User

作为设置
class User < ActiveRecord::Base
  validate :name, presence: true, uniqueness: { case_sensitive: false }, on: :create
  validate :password, presence: true, format: { with: /\A[a-zA-z]*\z/ }
end

看到几种测试方法:

it { expect(user).to validate_presence_of(:name).on(:create) } 

it do
  user = User.create(name: '')

  expect(user.errors[:name]).to be_present
end

我的主要问题是哪种方法更好,为什么?可以建议我采用不同的方法吗?

其他问题:

  • 我应该测试多少?作为一个例子,我可以为正则表达式编写这么多测试,但它对于维护来说将是地狱。
  • 您认为这个示例中的完整测试覆盖率是多少?

2 个答案:

答案 0 :(得分:1)

应该使用这两个,因为:

it { expect(user).to validate_presence_of(:name).on(:create) } 

=&GT;您期望validate_presence_of应该在create上运行,这应该是模型的测试用例

it do
  user = User.create(name: '')
  expect(user.errors[:name]).to be_present
end

=&GT;在使用输入创建用户时,您会产生副作用,因此这应该是控制器的测试用例

为什么你不应该删除其中一个:

  • 删除第一个测试用例:如果您执行数据库验证级别会发生什么,您希望进行有效的记录级别验证

  • 删除第二个测试用例:控制器上发生了什么事实上会创建一个新的User,您如何期待错误返回!

答案 1 :(得分:1)

以下功能:

  • Rails能够验证模型上是否存在任意值
  • errors被添加到对象中,以便在配置验证时缺少该属性

包含在Rails本身的测试中(具体来说,在ActiveModel tests中)。

这需要编写 config 的测试,其中包含您的应用程序的业务逻辑,例如验证特定 {的存在特定 name课程的{1}}属性等。在我看来,shoulda-matchers gem的匹配者应该为您提供:

User

我认为除非你有你想要测试的错误的特定自定义错误消息(即你已经覆盖了默认的Rails),然后可以删除RSpec.describe User, type: :model do subject(:user) { build(:user) } # assuming you're using FactoryGirl describe 'validations' do specify 'for name' do expect(user).to validate_presence_of(:name).on(:create) # NOTE: saving here is needed to test uniqueness amongst users in # the database user.save expect(user).to validate_uniqueness_of(:name) end specify 'for password' do expect(user).to validate_presence_of(:password) expect(user).to allow_value('abcd').for(:password) expect(user).to_not allow_value('1234').for(:password) end end end 之类的测试(即使你有自定义错误,我仍然认为它们具有可疑价值,因为如果您将应用程序国际化,这些消息将依赖于区域设置,因此我会测试功能规范中expect(user.errors[:name]).to be_present上某些错误的显示代替)。

  

我可以为正则表达式编写这么多测试,但这对于维护来说是很难的。

我认为在测试page的验证时你不能真正解决这个问题,所以我建议你写一些有代表性的测试用例,然后在发现任何问题时添加/删除这些案例错过了,例如:

format
  

您认为这个示例中的完整测试覆盖率是多少?

如上所述,在编写单位规格时,我从SimpleCov等报告中获得了100%的代码覆盖率。