You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带标签日志编写RSpec?断言时方法被Mock而非Stub/Spy的问题

问题解决方法

错误原因是have_received断言要求目标对象是**Spy(间谍)**或被存根的对象,而你当前的Rails.logger是Mock对象,Mock不会记录方法调用的详情,无法满足断言需求。

解决步骤:

  • 先将Rails.logger转为Spy对象,在测试开始前添加存根或直接替换为spy实例:
    # 方法1:用allow存根,自动转为Spy
    allow(Rails.logger).to receive(:info)
    
    # 方法2:直接替换为spy实例
    Rails.logger = spy('Logger')
    
  • 另外注意:代码里的Time.zone.now在执行和断言时的时间会有偏差,直接对比哈希会失败,要用时间匹配器模糊校验。

修正后的完整测试代码:

# 测试前置:将logger转为Spy
before do
  allow(Rails.logger).to receive(:info)
end

it 'logs mail details correctly' do
  # 执行触发logger.info的代码
  logger.tagged(mail.message_id) do
    logger.info({ 
      to: Array(mail.to).join(', '),
      from: mail.from,
      subject: mail.subject,
      time: Time.zone.now,
      headers: mail.header,
      errors: mail.errors,
      delivery_status_part: mail.delivery_status_part,
      message_id: mail.message_id 
    })
  end

  # 断言时用时间匹配器处理time字段
  expect(Rails.logger).to have_received(:info).with(hash_including(
    to: Array(mail.to).join(', '),
    from: mail.from,
    subject: mail.subject,
    time: be_within(1.second).of(Time.zone.now),
    headers: mail.header,
    errors: mail.errors,
    delivery_status_part: mail.delivery_status_part,
    message_id: mail.message_id 
  ))
end

说明:

  • allow(Rails.logger).to receive(:info)会把logger变成Spy,记录所有info方法的调用参数,让have_received能正常工作。
  • hash_including用来校验哈希的指定字段,配合be_within处理时间的微小差异,避免因时间戳不一致导致断言失败。

内容的提问来源于stack exchange,提问作者Priya Lorha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:05:28