GTD*_*Dev 36 testing validation rspec ruby-on-rails activemodel
我有以下验证器:
# Source: http://guides.rubyonrails.org/active_record_validations_callbacks.html#custom-validators
# app/validators/email_validator.rb
class EmailValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
object.errors[attribute] << (options[:message] || "is not formatted properly")
end
end
end
Run Code Online (Sandbox Code Playgroud)
我希望能够在我的lib目录中的RSpec中测试它.到目前为止的问题是我不知道如何初始化EachValidator
.
Nea*_*eal 67
我不是其他方法的忠实粉丝,因为它将测试与实现联系得太紧密了.此外,它很难遵循.这是我最终使用的方法.请记住,这是对我的验证员实际做了什么的粗略过度简化...只是想更简单地证明它.肯定会有优化
class OmniauthValidator < ActiveModel::Validator
def validate(record)
if !record.omniauth_provider.nil? && !%w(facebook github).include?(record.omniauth_provider)
record.errors[:omniauth_provider] << 'Invalid omniauth provider'
end
end
end
Run Code Online (Sandbox Code Playgroud)
相关规范:
require 'spec_helper'
class Validatable
include ActiveModel::Validations
validates_with OmniauthValidator
attr_accessor :omniauth_provider
end
describe OmniauthValidator do
subject { Validatable.new }
context 'without provider' do
it 'is valid' do
expect(subject).to be_valid
end
end
context 'with valid provider' do
it 'is valid' do
subject.stubs(omniauth_provider: 'facebook')
expect(subject).to be_valid
end
end
context 'with unused provider' do
it 'is invalid' do
subject.stubs(omniauth_provider: 'twitter')
expect(subject).not_to be_valid
expect(subject).to have(1).error_on(:omniauth_provider)
end
end
end
Run Code Online (Sandbox Code Playgroud)
基本上我的方法是创建一个虚假对象"Validatable",这样我们就可以在其上实际测试结果,而不是对实现的每个部分都有期望
Gaz*_*ler 42
这是一个快速的规范,我敲了那个文件,它运作良好.我认为存根可能会被清除,但希望这足以让你开始.
require 'spec_helper'
describe "EmailValidator" do
before(:each) do
@validator = EmailValidator.new({:attributes => {}})
@mock = mock('model')
@mock.stub("errors").and_return([])
@mock.errors.stub('[]').and_return({})
@mock.errors[].stub('<<')
end
it "should validate valid address" do
@mock.should_not_receive('errors')
@validator.validate_each(@mock, "email", "test@test.com")
end
it "should validate invalid address" do
@mock.errors[].should_receive('<<')
@validator.validate_each(@mock, "email", "notvalid")
end
end
Run Code Online (Sandbox Code Playgroud)
我建议为测试目的创建一个匿名类,例如:
require 'spec_helper'
require 'active_model'
require 'email_validator'
RSpec.describe EmailValidator do
subject do
Class.new do
include ActiveModel::Validations
attr_accessor :email
validates :email, email: true
end.new
end
describe 'empty email addresses' do
['', nil].each do |email_address|
describe "when email address is #{email_address}" do
it "does not add an error" do
subject.email = email_address
subject.validate
expect(subject.errors[:email]).not_to include 'is not a valid email address'
end
end
end
end
describe 'invalid email addresses' do
['nope', '@', 'foo@bar.com.', '.', ' '].each do |email_address|
describe "when email address is #{email_address}" do
it "adds an error" do
subject.email = email_address
subject.validate
expect(subject.errors[:email]).to include 'is not a valid email address'
end
end
end
end
describe 'valid email addresses' do
['foo@bar.com', 'foo@bar.bar.co'].each do |email_address|
describe "when email address is #{email_address}" do
it "does not add an error" do
subject.email = email_address
subject.validate
expect(subject.errors[:email]).not_to include 'is not a valid email address'
end
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
这样可以防止Validatable
在多个规范中引用诸如之类的硬编码类,由于不相关的验证之间存在交互,您将尝试进行单独的测试,从而导致意外的行为和难以调试的行为。
受到@Gazler 回答的启发,我想出了以下内容;嘲笑模型,但ActiveModel::Errors
用作错误对象。这大大减少了嘲笑。
require 'spec_helper'
RSpec.describe EmailValidator, type: :validator do
subject { EmailValidator.new(attributes: { any: true }) }
describe '#validate_each' do
let(:errors) { ActiveModel::Errors.new(OpenStruct.new) }
let(:record) {
instance_double(ActiveModel::Validations, errors: errors)
}
context 'valid email' do
it 'does not increase error count' do
expect {
subject.validate_each(record, :email, 'test@example.com')
}.to_not change(errors, :count)
end
end
context 'invalid email' do
it 'increases the error count' do
expect {
subject.validate_each(record, :email, 'fakeemail')
}.to change(errors, :count)
end
it 'has the correct error message' do
expect {
subject.validate_each(record, :email, 'fakeemail')
}.to change { errors.first }.to [:email, 'is not an email']
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
16767 次 |
最近记录: |