如何仅监视 ActiveSupport::Notifications #instrument 的一个调用,而不是全部
How to spy just one call of ActiveSupport::Notifications #instrument, not all of them
我正在做一个 Rspec 测试来检查 ActiveSupport::Notification.instrument
是否被调用了一些参数。
问题是为了使这个测试需要 FactoryBot
构建一些对象,但是当我试图监视 ActiveSupport::Notification.instrument
时,我总是得到一个错误:
ActiveSupport::Notifications received :instrument with unexpected arguments
expected: (:asd)
got: ("factory_bot.run_factory", {:factory=>#<FactoryBot::Factory:0x005569b6d30, @al... nil, dispatch: nil, distribution_state: 2, main_category_id: nil>}, :strategy=>:build, :traits=>[]})
FactoryBot 似乎调用了 activesupport,所以当我出于测试目的模拟它时,我最终模拟得太远了...
代码示例:
class:
class SomeObject
def initialize(something)
#some code
end
def my_method
ActiveSupport::Notifications.instrument :asd
end
end
规格:
describe "#my_method" do
let(:some_object) { build :some_object }
before do
allow(ActiveSupport::Notifications).to receive(:instrument).with :asd
end
it "calls notifier" do
described_class.new(some_object).my_method
expect(ActiveSupport::Notifications).to have_received(:instrument).with :asd
end
end
我怎样才能模拟我的调用而不是 FactoryBot 的调用。
我只在嘲笑 :asd
之前再用一个 allow
来管理它:
allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
还有其他(更好的)方法吗?
我通常会避免嘲笑。
我遇到了类似的问题,下面是我如何解决的:
describe "#my_method" do
let(:some_object) { build :some_object }
before { record_events }
it "calls notifier" do
described_class.new(some_object).my_method
# Make sure your event was triggered
expect(events.map(&:name)).to include('asd')
# Check number of events
expect(events).to be_one
# Check contents of event payload
expect(events.first.payload).to eq({ 'extra' => 'context' })
# Even check the duration of an event
expect(events.first.duration).to be < 3
end
private
attr_reader :events
def record_events
@events = []
ActiveSupport::Notifications.subscribe(:asd) do |*args| #
@events << ActiveSupport::Notifications::Event.new(*args)
end
end
end
相对于模拟的优势
- 不再有奇怪的副作用
- 按预期使用
ActiveSupport::Notifications
ActiveSupport::Notifications::Event
wrapper gives you nice extras like #duration
- 轻松检查是否有其他事件被触发
- 仅查看与名称匹配的事件的能力 - 使用
ActiveSupport::Notifications.subscribe(/asd/)
对事件名称进行部分匹配
- 更好的可读性 - 检查事件数组更具可读性
模拟的缺点
- 更多代码
- 改变
@events
数组
- 如果您在
teardown
上不清除 @events
,则测试之间可能存在依赖关系
我正在做一个 Rspec 测试来检查 ActiveSupport::Notification.instrument
是否被调用了一些参数。
问题是为了使这个测试需要 FactoryBot
构建一些对象,但是当我试图监视 ActiveSupport::Notification.instrument
时,我总是得到一个错误:
ActiveSupport::Notifications received :instrument with unexpected arguments
expected: (:asd)
got: ("factory_bot.run_factory", {:factory=>#<FactoryBot::Factory:0x005569b6d30, @al... nil, dispatch: nil, distribution_state: 2, main_category_id: nil>}, :strategy=>:build, :traits=>[]})
FactoryBot 似乎调用了 activesupport,所以当我出于测试目的模拟它时,我最终模拟得太远了...
代码示例:
class:
class SomeObject
def initialize(something)
#some code
end
def my_method
ActiveSupport::Notifications.instrument :asd
end
end
规格:
describe "#my_method" do
let(:some_object) { build :some_object }
before do
allow(ActiveSupport::Notifications).to receive(:instrument).with :asd
end
it "calls notifier" do
described_class.new(some_object).my_method
expect(ActiveSupport::Notifications).to have_received(:instrument).with :asd
end
end
我怎样才能模拟我的调用而不是 FactoryBot 的调用。
我只在嘲笑 :asd
之前再用一个 allow
来管理它:
allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
还有其他(更好的)方法吗?
我通常会避免嘲笑。
我遇到了类似的问题,下面是我如何解决的:
describe "#my_method" do
let(:some_object) { build :some_object }
before { record_events }
it "calls notifier" do
described_class.new(some_object).my_method
# Make sure your event was triggered
expect(events.map(&:name)).to include('asd')
# Check number of events
expect(events).to be_one
# Check contents of event payload
expect(events.first.payload).to eq({ 'extra' => 'context' })
# Even check the duration of an event
expect(events.first.duration).to be < 3
end
private
attr_reader :events
def record_events
@events = []
ActiveSupport::Notifications.subscribe(:asd) do |*args| #
@events << ActiveSupport::Notifications::Event.new(*args)
end
end
end
相对于模拟的优势
- 不再有奇怪的副作用
- 按预期使用
ActiveSupport::Notifications
ActiveSupport::Notifications::Event
wrapper gives you nice extras like#duration
- 轻松检查是否有其他事件被触发
- 仅查看与名称匹配的事件的能力 - 使用
ActiveSupport::Notifications.subscribe(/asd/)
对事件名称进行部分匹配 - 更好的可读性 - 检查事件数组更具可读性
模拟的缺点
- 更多代码
- 改变
@events
数组 - 如果您在
teardown
上不清除
@events
,则测试之间可能存在依赖关系