Ruby on rails 使用RSpec测试Rails模型验证,而不测试AR本身 使用RSpec测试Rails模型验证,而不测试AR本身
作为设置,我们有型号Ruby on rails 使用RSpec测试Rails模型验证,而不测试AR本身 使用RSpec测试Rails模型验证,而不测试AR本身,ruby-on-rails,ruby,unit-testing,testing,rspec,Ruby On Rails,Ruby,Unit Testing,Testing,Rspec,作为设置,我们有型号用户: 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 或 我的主要问题是哪种方法更好,为什么?你能给我建议不同的方法吗? 其他问题:
用户
:
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) }
=>您希望在create
上运行validate\u presence\u
,这应该是模型的测试用例
it do
user = User.create(name: '')
expect(user.errors[:name]).to be_present
end
=>在使用输入创建用户时,您预期会产生副作用,因此这应该是控制器的测试用例
为什么不应删除其中的1个:
- 删除第一个测试用例:如果改为使用数据库验证级别,会发生什么情况?您希望使用活动记录级别的验证
- 删除第二个测试用例:控制器上发生的事情实际上创建了一个新的
,您如何期望错误返回用户
- 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
我认为,除非您有特定的自定义错误消息用于您想要测试的错误(即您已经覆盖了默认的Rails错误),否则可以删除像expect(user.errors[:name])这样的测试(即使您有自定义错误,我仍然认为它们的价值值得怀疑,因为如果您将应用程序国际化,这些消息将取决于语言环境,因此我会在特性规范的页面上测试某种错误的显示)
我可以为正则表达式编写这么多的测试,但这将是维护的地狱
我认为在测试格式的验证时,您无法真正绕过这一点,因此我建议您只编写一些具有代表性的测试用例,然后在发现任何可能遗漏的问题时添加/删除这些用例,例如:
# use a `let` or extract out into a test helper method
let(:valid_passwords) do
['abcd', 'ABCD', 'AbCd'] # etc etc
end
describe 'validations' do
specify 'for password' do
valid_passwords.each do |password|
expect(user).to allow_value(password).for(:password)
end
end
end
在这个例子中,您认为完整的测试覆盖率是多少
我已经从报告中获得了100%的代码覆盖率,比如在编写如上所述的单元规范时。仅供参考,
matcher的validate\u presence\u不是RSpec内置的,它是由shoulda matchers gem添加的:第一个更紧凑,所以更好,它意味着第二个方法的功能,所以您建议第二个测试用例是c控制器单元测试?所以你更喜欢第一个模型单元测试?是的,这就是我在当前项目中的想法和使用,我们通常测试行为(调用什么)和测试副作用(发生什么)!
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
# use a `let` or extract out into a test helper method
let(:valid_passwords) do
['abcd', 'ABCD', 'AbCd'] # etc etc
end
describe 'validations' do
specify 'for password' do
valid_passwords.each do |password|
expect(user).to allow_value(password).for(:password)
end
end
end