Ruby 什么时候你会在Rspec中使用间谍而不是双打?
我能理解测试双精度在Rspec中的应用。您可能需要测试一个方法,该方法有一个执行昂贵网络查询的对象。因此,您可以使用填充(test double)返回昂贵操作所需的值:Ruby 什么时候你会在Rspec中使用间谍而不是双打?,ruby,rspec,Ruby,Rspec,我能理解测试双精度在Rspec中的应用。您可能需要测试一个方法,该方法有一个执行昂贵网络查询的对象。因此,您可以使用填充(test double)返回昂贵操作所需的值: class Contact def update @api_result = AmazonAPI.perform_expensive_task self.status = @api_result['status'] self.last_checked = @api_result['last_check
class Contact
def update
@api_result = AmazonAPI.perform_expensive_task
self.status = @api_result['status']
self.last_checked = @api_result['last_checked']
save!
end
end
describe Contact do
subject { Contact.new }
describe '#update' do
it "updates contact with api criteria" do
api = double('Amazon API')
allow(api).to receive(:perform_expensive_task).and_return({ status: 1, last_checked: Time.now })
subject.update
expect(subject.status).to eq 1
end
end
end
我们需要测试update方法,但不想测试API查询。因此,我们使用一个测试双精度并将其存根,以解决需求
但后来我遇到了间谍。我看不出这有什么用。这是本教程中提供的示例:
let(:order) do
spy('Order', process_line_items: nil, charge_credit_card: true, send_email: true)
end
before(:example) do
order.process_line_items
order.charge_credit_card
order.send_email
end
it 'calls #process_line_items on the order' do
expect(order).to have_received(:process_line_items)
end
it 'calls #charge_credit_card on the order' do
expect(order).to have_received(:charge_credit_card)
end
it 'calls #send_email on the order' do
expect(order).to have_received(:send_email)
end
这个特定的示例显式地调用了三个方法,稍后将检查是否调用了这三个方法。当然,它叫他们。它在测试中做对了。在实际情况下,我应该在什么时候使用spies?Spice跟踪对其进行的呼叫(特别是它发送的消息)。因此,每当需要断言对合作者进行了特定调用时,您都会使用间谍 典型的用例是根据输入检查您的实现是否正在使用外部协作器。假设您打算有条件地记录日志,或者您可以检查作业是否使用特定参数排队,或者是否调用了某个mailer方法 间谍是保证你的目标正确合作的工具 更新 示例可以在@meta的答案中找到 带有代码的简单用例是logger one:
class SomeCommand
def call(arg:, other:)
if arg <= 0
logger.warn("args should be positive")
else
logger.debug("all fine")
end
# more
end
def logger
Rails.logger # for instance
end
end
describe SomeCommand
let(:logger) { spy('Logger') }
# replace collaborator
before { allow(subject).to receive(:logger) { logger } }
context 'with negative value' do
it 'warns' do
subject.call(arg: -1, other: 6)
expect(logger).to have_received(:warn)
expect(logger).not_to have_received(:debug)
end
end
context 'with positive value' do
it 'logs as debug' do
subject.call(arg: 1, other: 6)
expect(logger).not_to have_received(:warn)
expect(logger).to have_received(:debug)
end
end
end
class命令
def调用(参数:,其他:)
如果arg我会在上面再加一个案例什么
间谍给了你一些灵活性。如果需要检查是否调用了该方法,则可以在以下情况下使用模拟:
before do
expect(foo).to receive(:do_stuff)
end
specify do
bar.run
end
但是,
之前的并不是增加期望的最佳场所。你是。您可以这样做:
specify do
expect(foo).to receive(:do_stuff)
bar.run
end
但这样做看起来更好
before do
bar.run
end
specify do
expect(foo).to have_received(:do_stuff)
end
当有更多的东西需要检查时,你会有更干净的代码
before { bar.run }
specify do
expect(foo).to have_received(:do_stuff)
end
context 'with some special conditions' do
before { set_up_special_conditions }
specify do
expect(foo).not_to have_received(:do_stuff)
end
end
这也许没什么大不了的,你还可以继续生活
specify do
bar.run
expect(foo).to have_received(:do_stuff)
end
context 'with some special conditions' do
before { set_up_special_conditions } # * check the note at the bottom
specify do
bar.run
expect(foo).not_to have_received(:do_stuff)
end
end
但我认为定义上下文的一个好方法是只明确提到本质上的区别(set\u-up\u-special\u-conditions
和expect(foo)。而不是明确提到接收(:do\u-stuff)
)。任何与“上面”上下文没有区别的内容都不应出现在更具体的“下面”上下文中。它有助于管理更大的规格
*注意:我不确定以这种方式定义的块之前的顺序,查看之后,我也不确定该顺序是否得到保证。不能马上检查。但是为了演示的目的,我们可以假设{set\u up\u special\u conditions}之前的将在{bar.run}
之前运行。但如果不是这样的话——还有其他方法可以确保这一点,但这似乎超出了这个问题的范围。“您无法设置spy返回的内容”这并不完全正确。您可以使用allow(spy.to_receive(:msg)
使用任何响应配置机制,在spy上设置响应,就像在double上设置响应一样。文档在感谢中,您是正确的。我的意思是,有了这个接口,你(显然)不能做像这样的事情,。让_接收(),然后_返回(某物)
,你确实可以,用部分双倍。纯间谍没有原始实现的支持。如果您需要检查原始推进,您必须执行allow(partial.),以接收(:msg.)和_wrap_original{| m,*args | m.call(*args)。点击{| resp |@resp=resp}
。然后您可以在调用某个对象后对其进行期望(@resp.)。再说一次,这不是间谍,而是带有包装的局部涂鸦。