如何在 Rspec 中使用一个参数和一个块测试一次方法调用


class ExternalObject
attr_accessor :external_object_attribute
def update_external_attribute(options = {})
self.external_object_attribute = [1,nil].sample
end
end
class A
attr_reader :my_attr, :external_obj
def initialize(external_obj)
@external_obj = external_obj
end
def main_method(options = {})
case options[:key]
when :my_key
self.my_private_method(:my_key) do 
external_obj.update_external_attribute(reevaluate: true)
end
else
nil
end
end
private
def my_private_method(key)
old_value = key
external_object.external_object_attribute = nil
yield
external_object.external_object_attribute = old_value if external_object.external_object_attribute.nil?
end
end

我想在options[:key] == :my_key时测试以下内容main_method

my_private_method使用参数:my_key调用一次,并且它有一个块{external_obj.update_external_attribute(reevaluate: true) },它使用参数reevaluate: true调用external_objupdate_external_attribute一次。

我能够用:my_key参数测试my_private_method电话一次。

expect(subject).to receive(:my_private_method).with(:my_key).once

但是,如何测试期望的剩余部分呢?

谢谢

如果您也发布测试,可能会更容易回答您的问题。 设置,执行和评估/期望。

你可以在这个较老的问题中找到一个简短的答案。

您可以找到有用的阅读有关yield匹配器的信息。

如果您还没有嘲笑ExternalObject,我建议您嘲笑。但是除非您发布实际的测试代码,否则我无法判断。

我将回答你的问题。但是,接下来我将解释为什么你不应该这样做,并向你展示一个更好的方法。

在您的测试设置中,您需要允许双精度值屈服,以便代码将落入您的块。

RSpec.describe A do
subject(:a) { described_class.new(external_obj) }
let(:external_obj) { instance_double(ExternalObject) }
describe '#main_method' do
subject(:main_method) { a.main_method(options) }
let(:options) { { key: :my_key } }
before do
allow(a).to receive(:my_private_method).and_yield
allow(external_obj).to receive(:update_external_attribute)
main_method
end
it 'does something useful' do
expect(a)
.to have_received(:my_private_method)
.with(:my_key)
.once
expect(external_obj)
.to have_received(:update_external_attribute)
.with(reevaluate: true)
.once
end
end
end

这行得通。测试通过。RSpec 是一个强大的工具。而且,它会让你侥幸逃脱。但是,这并不意味着你应该这样做。测试私有方法总是一个坏主意。

测试应仅测试类的公共接口。 否则,您将自己锁定在当前实现中,导致在重构类的内部工作时测试失败 - 即使您没有更改对象的外部可见行为也是如此。

这是一个更好的方法:

RSpec.describe A do
subject(:a) { described_class.new(external_obj) }
let(:external_obj) { instance_double(ExternalObject) }
describe '#main_method' do
subject(:main_method) { a.main_method(options) }
let(:options) { { key: :my_key } }
before do
allow(external_obj).to receive(:update_external_attribute)
allow(external_obj).to receive(:external_object_attribute=)
allow(external_obj).to receive(:external_object_attribute)
main_method
end
it 'updates external attribute' do
expect(external_obj)
.to have_received(:update_external_attribute)
.with(reevaluate: true)
.once
end
end
end

请注意,对私有方法的期望已消失。现在,测试仅依靠class Aclass ExternalObject的公共接口。

希望有帮助。

相关内容

  • 没有找到相关文章

最新更新