动态类
验证实例替身不支持类报告不存在的方法,因为需要实际的类实例才能进行验证。当使用 method_missing
时,这种情况很常见。
有几种解决方法。如果对象已经加载,您可以考虑使用 object_double
,但这在隔离测试时无法使用。或者,您可以直接实现方法(调用 super
返回 method_missing
定义)。
其中一些类可能具有在运行时在对象上定义这些方法的方法。(例如,ActiveRecord
这样做是为了从数据库列定义方法。)对于这些情况,我们提供了一个 API,可以在创建时用于自定义验证替身。我们在 rspec-rails
中自己使用它来为您设置一些便利功能。
这些类型的 method 在类级别(使用 class_double
)得到支持,但是,由于 respond_to?
可以直接在类上查询。
背景
给定一个名为“lib/fake_active_record.rb”的文件,其中包含
class FakeActiveRecord
COLUMNS = %w[name email]
def respond_to_missing?(method_name)
COLUMNS.include?(method_name.to_s) || super
end
def method_missing(method_name, *args)
if respond_to?(method_name)
instance_variable_get("@#{method_name}")
else
super
end
end
def self.define_attribute_methods
COLUMNS.each do |name|
define_method(name) { instance_variable_get("@#{name}") }
end
end
end
给定一个名为“spec/user_spec.rb”的文件,其中包含
require 'user'
RSpec.describe User do
it 'can be doubled' do
instance_double("User", :name => "Don")
end
end
使用 method missing 失败
给定一个名为“lib/user.rb”的文件,其中包含
require 'fake_active_record'
class User < FakeActiveRecord
end
当我运行 rspec spec/user_spec.rb
时
那么输出应该包含“1 个示例,1 个失败”。
使用显式定义的解决方法
给定一个名为“lib/user.rb”的文件,其中包含
require 'fake_active_record'
class User < FakeActiveRecord
def name; super end
def email; super end
end
当我运行 rspec spec/user_spec.rb
时
那么所有示例都应该通过。
使用回调的解决方法
给定一个名为“lib/user.rb”的文件,其中包含
require 'fake_active_record'
class User < FakeActiveRecord
end
以及一个名为“spec/fake_record_helper.rb”的文件,其中包含
RSpec.configuration.mock_with(:rspec) do |config|
config.before_verifying_doubles do |reference|
reference.target.define_attribute_methods
end
end
#
# or you can use:
#
# RSpec::Mocks.configuration.before_verifying_doubles do |reference|
# reference.target.define_attribute_methods
# end
当我运行 rspec -r fake_record_helper spec/user_spec.rb
时
那么所有示例都应该通过。