我有一个具有冰糕类型签名定义的方法。 尝试在使用RSpec的测试中模拟此方法时,出现类型不匹配错误。 我试图了解如何解决此问题并添加基于RSpec的测试而不影响冰糕类型检查。
sig {params(login_context: LoginContext, company_id: String).returns(T::Boolean)}
def populate_dummy_data(login_context, company_id)
测试代码:
@login_context = double(LoginContext, :requester => @requester) # Creates an instance of type Rspec::Mocks::double
错误:
expected no Exception, got #<TypeError: Parameter ‘login_context’: Expected type LoginContext, got type RSpec::Mocks::Double wit...a_populator_spec.rb:42
答案 0 :(得分:2)
Mocha模拟(测试中的存根)默认情况下不会通过任何类型检查。这是故意的,被认为是功能;裸机使测试变得脆弱,并且无论重构类型如何,重构代码时都容易引起问题。
当尝试使用未通过类型检查的Mocha模拟测试方法时,建议重写测试以不使用Mocha模拟。要么:
.stubs
仅替换某些方法。在最坏的情况下,您可以对is_a?
进行存根处理,以使Mocha模拟通过类型检查,但是请避免这样做。它会导致测试变脆,并使代码难以推理。如果必须:
# NOT RECOMMENDED!
fake_llama = stub
fake_llama.stubs(:llama_count).returns(17)
fake_llama.stubs(:is_a?).with(M::Llama).returns(true)
我不熟悉RSpec的模拟与Mocha的模拟之间的区别(在开发Sorbet的Stripe,我们使用Mocha),但原理应该相同。
答案 1 :(得分:1)
解决方案1:
将instance_double
与适当的类一起使用并模拟is_a?
。为此,请在全球范围内进行猴子补丁:
require 'rspec/mocks'
class RSpec::Mocks::InstanceVerifyingDouble
def is_a?(expected)
@doubled_module.target <= expected || super
end
end
解决方案2:
当由模拟引起时不要引发异常。 除非使用了模拟程序,否则Sorbet仍然可以执行类型检查。
T::Configuration.inline_type_error_handler = proc do |error|
raise error unless error.message.include? "got type RSpec::Mocks"
end
T::Configuration.call_validation_error_handler = proc do |_signature, opts|
raise TypeError.new(opts[:pretty_message]) unless opts[:message].include? "got type RSpec::Mocks"
end