我想知道 RSpec 如何实现这一点:
expect( MyObject ).to receive(:the_answer).and_return(42)
Run Code Online (Sandbox Code Playgroud)
不RSpec的利用define_singleton_method注入:the_answer到MyObject?
那可以工作。让我们假设这是MyObject看起来的样子:
class MyObject
def self.the_answer
21 * 2
end
end
Run Code Online (Sandbox Code Playgroud)
该注入的 the_answer方法可能包含这样的事情:
@the_answer_called = true
42
Run Code Online (Sandbox Code Playgroud)
但是,RSpec 如何将类恢复到未模拟状态?它如何恢复它以便MyObject.the_answer“真正”再次返回 42 ?(通过 21 * 2)
自从写这个问题以来,我认为它没有。类方法保持模拟直到 RSpec 停止运行。
但是,(这是问题的关键)如何撤消define_singleton_method?
我认为最简单的方法是old_object = Object.dup在define_singleton_method使用之前运行,但是,我如何恢复old_object到Object?
当我想做的只是恢复一个类方法时,这也没有让我感到高效。虽然目前这不是一个问题,但也许将来我还想保持某些实例变量MyObject完好无损。是否有一种非hacky 的方式来复制代码 ( 21 * 2) 并将其重新定义为the_answerviadefine_singleton_method而不是完全替换Object?
欢迎所有想法,我绝对想知道如何制作Object …
在替换原始的模拟方法之前,有没有办法模拟一个方法一次且每个期望只模拟一次?
我认为这样的事情会起作用(注意once)
class Klass
def self.meth
'baz'
end
end
describe Klass do
subject{ described_class.meth }
before{ allow(described_class).to receive(:meth).once.and_return('foo') }
it{ is_expected.to eq 'foo' }
context 'throwing in a context just to test' do
it{ is_expected.to eq 'foo' }
it{ is_expected.to eq 'foo' }
it{ is_expected.to eq 'foo' }
it 'only mocks once' do
expect(subject).to eq 'foo'
expect(subject).to eq 'baz' # this is the key
end # pass
end
end
Run Code Online (Sandbox Code Playgroud)
不幸的是,我收到此错误:
(Klass (class)).meth(no args)
expected: 1 time with any …Run Code Online (Sandbox Code Playgroud)