在一些测试中,我想设置一个引发特定异常类的mock。因为这个特殊的异常很难在测试中示例化,所以我想使用double。
举个例子
class SomeError < StandardError
def initialize(some, random, params)
# ...
end
end
class SomeClass
def some_method
mocked_method
:ok
rescue SomeError
:ko
end
def mocked_method
true
end
end
describe SomeClass do
subject(:some_class) { described_class.new }
describe '#some_method' do
subject(:some_method) { some_class.some_method }
it { is_expected.to be :ok }
context 'when #mocked_method fails' do
before do
allow(some_class).to receive(:mocked_method)
.and_raise(instance_double(SomeError))
end
it { is_expected.to be :ko }
end
end
end
但是,运行此测试失败,并显示以下消息。
Failure/Error:
mocked_method
TypeError:
exception class/object expected
奇怪的是,如果我用StandardError
替换SomeError
,它工作得很好。
class SomeClass
def some_method
mocked_method
:ok
rescue StandardError
:ko
end
def mocked_method
true
end
end
describe SomeClass do
subject(:some_class) { described_class.new }
describe '#some_method' do
subject(:some_method) { some_class.some_method }
it { is_expected.to be :ok }
context 'when #mocked_method fails' do
before do
allow(some_class).to receive(:mocked_method)
.and_raise(instance_double(StandardError))
end
it { is_expected.to be :ko }
end
end
end
这里发生了什么事?在模拟StandardError
时是否有一些边缘情况?或者,有没有更好的方法来模拟难以示例化的异常类?**
2条答案
按热度按时间siv3szwd1#
问题说明
TypeError
由Kernel#raise
引起。RSpec::Mocks::MessageExpectation#and_raise
将对Kernel#raise
的调用 Package 在稍后调用的Proc
(如图所示)中。Kernel#raise
接受以下内容:$!
中引发异常,或者如果$!
是nil
则引发RuntimeError
“;或RuntimeError
,字符串作为一个消息。";或Exception
或另一个对象,当发送exception
消息时返回一个Exception
对象”* -此Exception
将被引发在你的例子中,
instance_double(SomeError)
不是以上任何一个,因此Kernel#raise
抛出一个TypeError
。同样的情况可以通过以下方式复制:红鲱鱼
StandardError
工作的原因并不是你想的那样。相反,
StandardError
只是 * 看起来 * 工作,因为SomeClass#some_method
正在拯救StandardError
,而TypeError
是StandardError
(继承自StandardError
)。在这种情况下,TypeError
仍在上升,它只是在这个过程中被拯救。您可以通过将
and_raise(instance_double(StandardError))
更改为and_raise(instance_double(SomeError))
(或任何其他不符合Kernel#raise
接受的参数的参数)来证明这一点,只要SomeClass#some_method
拯救StandardError
或TypeError
,代码仍然会通过。解决方案?
虽然我不完全理解你所受到的限制(例如:* “那个特殊的异常很难在测试中示例化”*),并且完全建议只示例化一个
SomeError
,您可以通过简单地创建一个继承自SomeError
的异常作为模拟来实现您的目标。例如
ia2d9nvy2#
TypeError
消息实际上来自pry
gem。它检查引发的错误是否通过了exception.is_a?(Exception)
检查。示例double不会对is_a?
检查响应true。更常见的方法是使用参数的某些值引发错误的示例: