期望模拟结果接收方法
Expect mock result to receive method
我正在尝试模拟一个 class,这样我就可以期望它被实例化,然后调用某个方法。
我试过了:
expect(MyPolicy).
to receive(:new).
and_wrap_original do |method, *args|
expect(method.call(*args)).to receive(:show?).and_call_original
end
但我得到的只是:
undefined method `show?' for #RSpec::Mocks::VerifyingMessageExpectation:0x0055e9ffd0b530
我试过提供一个块并首先调用原始方法(:new 和 :show?,我必须先绑定),但错误总是一样。
我知道 expect_any_instance_of
,但它被认为是代码异味,所以我正在尝试找到另一种正确的方法。
上下文:我有专家政策,我想检查它是否已被调用
我也试过了,同样的错误:
ctor = policy_class.method(:new)
expect(policy_class).
to receive(:new).
with(user, record) do
expect(ctor.call(user, record)).to receive(query).and_call_original
end
你破产了MyPolicy.new
。
您的 new
包装器没有 return 新的 MyPolicy 对象。它 return 是 expect(method.call(*args)).to receive(:show?).and_call_original
的结果,它是一个 MessageExpectation。
相反,您可以确保新对象 return 使用 tap
编辑。
# This is an allow. It's not a test, it's scaffolding for the test.
allow(MyPolicy).to receive(:new)
.and_wrap_original do |method, *args|
method.call(*args).tap do |obj|
expect(obj).to receive(:show?).and_call_original
end
end
或者用老式的方法。
allow(MyPolicy).to receive(:new)
.and_wrap_original do |method, *args|
obj = method.call(*args)
expect(obj).to receive(:show?).and_call_original
obj
end
将这两个步骤分开通常会更简单。将 MyPolicy.new 模拟到 return 特定对象,然后期望调用显示?在那个对象上。
let(:policy) do
# This calls the real MyPolicy.new because policy is referenced
# when setting up the MyPolicy.new mock.
MyPolicy.new
end
before do
allow(MyPolicy).to receive(:new).and_return(policy)
end
it 'shows' do
expect(policy).to receive(:show?).and_call_original
MyPolicy.new.show?
end
这确实意味着 MyPolicy.new 总是 return 同一个对象。这是测试的优势,但可能会破坏某些东西。这更加灵活,因为它将脚手架与正在测试的内容分开。脚手架可以重复使用
RSpec.describe SomeClass do
let(:policy) {
MyPolicy.new
}
let(:thing) {
described_class.new
}
shared_context 'mocked MyPolicy.new' do
before do
allow(MyPolicy).to receive(:new).and_return(policy)
end
end
describe '#some_method' do
include_context 'mocked new'
it 'shows a policy' do
expect(policy).to receive(:show?).and_call_original
thing.some_method
end
end
describe '#other_method' do
include_context 'mocked MyPolicy.new'
it 'checks its policy' do
expect(policy).to receive(:check)
thing.other_method
end
end
end
最后,不可访问的构造函数调用对于测试来说是一个令人头疼的问题,而且它们不灵活。这是默认值,无法覆盖。
class SomeClass
def some_method
MyPolicy.new.show?
end
end
将其转换为具有默认值的访问器。
class SomeClass
attr_writer :policy
def policy
@policy ||= MyPolicy.new
end
def some_method
policy.show?
end
end
现在可以在测试中或其他任何地方访问。
RSpec.describe SomeClass do
let(:thing) {
described_class.new
}
describe '#some_method' do
it 'shows its policy' do
expect(thing.policy).to receive(:show?).and_call_original
thing.some_method
end
end
end
这是最稳健的选择。
我正在尝试模拟一个 class,这样我就可以期望它被实例化,然后调用某个方法。
我试过了:
expect(MyPolicy).
to receive(:new).
and_wrap_original do |method, *args|
expect(method.call(*args)).to receive(:show?).and_call_original
end
但我得到的只是:
undefined method `show?' for #RSpec::Mocks::VerifyingMessageExpectation:0x0055e9ffd0b530
我试过提供一个块并首先调用原始方法(:new 和 :show?,我必须先绑定),但错误总是一样。
我知道 expect_any_instance_of
,但它被认为是代码异味,所以我正在尝试找到另一种正确的方法。
上下文:我有专家政策,我想检查它是否已被调用
我也试过了,同样的错误:
ctor = policy_class.method(:new)
expect(policy_class).
to receive(:new).
with(user, record) do
expect(ctor.call(user, record)).to receive(query).and_call_original
end
你破产了MyPolicy.new
。
您的 new
包装器没有 return 新的 MyPolicy 对象。它 return 是 expect(method.call(*args)).to receive(:show?).and_call_original
的结果,它是一个 MessageExpectation。
相反,您可以确保新对象 return 使用 tap
编辑。
# This is an allow. It's not a test, it's scaffolding for the test.
allow(MyPolicy).to receive(:new)
.and_wrap_original do |method, *args|
method.call(*args).tap do |obj|
expect(obj).to receive(:show?).and_call_original
end
end
或者用老式的方法。
allow(MyPolicy).to receive(:new)
.and_wrap_original do |method, *args|
obj = method.call(*args)
expect(obj).to receive(:show?).and_call_original
obj
end
将这两个步骤分开通常会更简单。将 MyPolicy.new 模拟到 return 特定对象,然后期望调用显示?在那个对象上。
let(:policy) do
# This calls the real MyPolicy.new because policy is referenced
# when setting up the MyPolicy.new mock.
MyPolicy.new
end
before do
allow(MyPolicy).to receive(:new).and_return(policy)
end
it 'shows' do
expect(policy).to receive(:show?).and_call_original
MyPolicy.new.show?
end
这确实意味着 MyPolicy.new 总是 return 同一个对象。这是测试的优势,但可能会破坏某些东西。这更加灵活,因为它将脚手架与正在测试的内容分开。脚手架可以重复使用
RSpec.describe SomeClass do
let(:policy) {
MyPolicy.new
}
let(:thing) {
described_class.new
}
shared_context 'mocked MyPolicy.new' do
before do
allow(MyPolicy).to receive(:new).and_return(policy)
end
end
describe '#some_method' do
include_context 'mocked new'
it 'shows a policy' do
expect(policy).to receive(:show?).and_call_original
thing.some_method
end
end
describe '#other_method' do
include_context 'mocked MyPolicy.new'
it 'checks its policy' do
expect(policy).to receive(:check)
thing.other_method
end
end
end
最后,不可访问的构造函数调用对于测试来说是一个令人头疼的问题,而且它们不灵活。这是默认值,无法覆盖。
class SomeClass
def some_method
MyPolicy.new.show?
end
end
将其转换为具有默认值的访问器。
class SomeClass
attr_writer :policy
def policy
@policy ||= MyPolicy.new
end
def some_method
policy.show?
end
end
现在可以在测试中或其他任何地方访问。
RSpec.describe SomeClass do
let(:thing) {
described_class.new
}
describe '#some_method' do
it 'shows its policy' do
expect(thing.policy).to receive(:show?).and_call_original
thing.some_method
end
end
end
这是最稳健的选择。