我想了兩個自定義驗證運行規格:測試使用RSpec
spec/validators/email_validator_spec.rb
spec/validators/phone_validator_spec.rb
當我運行bundle exec rspec spec/validators/
的phone_validator_spec.rb
規範失敗:
1) PhoneValidator with a valid phone number should be valid
Failure/Error: subject.should be_valid
expected valid? to return true, got false
# ./spec/validators/phone_validator_spec.rb:20:in `block (4 levels) in <top (required)>'
# ./spec/validators/phone_validator_spec.rb:18:in `each'
# ./spec/validators/phone_validator_spec.rb:18:in `block (3 levels) in <top (required)>'
然而,當我運行規範單獨使用命令bundle exec rspec spec/validators/phone_validator_spec.rb
,它通過。
當我除去email_validator_spec.rb
然後phone_validator_spec.rb
通過使用命令bundle exec rspec spec/validators/
。
我希望在運行bundle exec rspec spec/validators/
時兩個規格都能通過。任何人都可以向我解釋發生了什麼?
更新: 二手探究性的提示打印出來的誤差散:
1) PhoneValidator with a valid phone number should be valid
Failure/Error: subject.errors.should == {}
expected: {}
got: #<ActiveModel::Errors:0x37b2460 @base=#<Validatable:0x37b2700 @validation_context=nil, @errors=#<ActiveModel::Errors:0x37b2460 ...>, @phone_number="1112223333">, @messages={:email=>["is invalid"]}> (using ==)
Diff:
@@ -1 +1,8 @@
+#<ActiveModel::Errors:0x37b2460
+ @base=
+ #<Validatable:0x37b2700
+ @errors=#<ActiveModel::Errors:0x37b2460 ...>,
+ @phone_number="1112223333",
+ @validation_context=nil>,
+ @messages={:email=>["is invalid"]}>
# ./spec/validators/phone_validator_spec.rb:21:in `block (4 levels) in <top (required)>'
# ./spec/validators/phone_validator_spec.rb:18:in `each'
# ./spec/validators/phone_validator_spec.rb:18:in `block (3 levels) in <top (required)>'
看來當兩個規範是運行Validatable
類定義組合。預期這種行爲?如果我使用不同的類名,則兩個規格都會通過。
規格/驗證/ phone_validator_spec.rb
require 'active_model'
require 'rspec/rails/extensions'
require File.expand_path('app/validators/phone_validator')
class Validatable
include ActiveModel::Validations
attr_accessor :phone_number
validates :phone_number, phone: true
end
describe PhoneValidator do
subject { Validatable.new }
describe "with a valid phone number" do
it "should be valid" do
phone_numbers = ["1112223333", "123222ABCD"]
phone_numbers.each do |phone_number|
subject.phone_number = phone_number
subject.should be_valid
end
end
end
end
應用程序/驗證/ phone_validator.rb
class PhoneValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
return if value.blank?
unless value =~ /^[A-Za-z0-9]{10}$/
object.errors[attribute] << (options[:message] || "is not formatted properly")
end
end
end
規格/驗證/ email_validator_spec.rb
require 'active_model'
require 'rspec/rails/extensions'
require File.expand_path('app/validators/email_validator')
class Validatable
include ActiveModel::Validations
attr_accessor :email
validates :email, email: true
end
describe EmailValidator do
subject { Validatable.new }
describe "with a valid email address" do
it "should be valid" do
addresses = %w[[email protected] [email protected] [email protected] [email protected]]
addresses.each do |valid_address|
subject.email = valid_address
subject.should be_valid
end
end
end
describe "with an invalid phone number" do
it "should be invalid" do
addresses = %w[[email protected],com user_at_foo.org [email protected]]
addresses.each do |invalid_address|
subject.email = invalid_address
subject.should be_invalid
end
end
end
end
應用程序/驗證/ email_validator.rb
require 'mail'
class EmailValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
begin
m = Mail::Address.new(value)
# We must check that value contains a domain and that value is an email address
r = m.domain && m.address == value
t = m.__send__(:tree)
# We need to dig into treetop
# A valid domain must have dot_atom_text elements size > 1
# [email protected] is excluded
# treetop must respond to domain
# We exclude valid email values like <[email protected]>
# Hence we use m.__send__(tree).domain
r &&= (t.domain.dot_atom_text.elements.size > 1)
rescue => e
r = false
end
object.errors[attribute] << (options[:message] || "is invalid") unless r
end
end
使用Rails 3.2.11,RSpec的護欄2.11.0
感謝您的提示。看起來兩個'Validatable'類定義導致了這個問題。我已經更新了我的問題。 –
感謝您的更新。我不希望規範互相依賴,所以我只是要給每個Validatable類一個獨特的名稱。我接受了你的建議,並刪除了救援例外。 –