首页 > 解决方案 > 如何测试 ActiveSupport::TaggedLogging

问题描述

我想测试作为代码一部分生成的特定日志。虽然测试起来似乎相当简单Rails.logger,但我将它包装在ActiveSupport::TaggedLogging其中,我无法使用它进行测试......

这是我有的两种方法:

  def logger
    @logger = ActiveSupport::TaggedLogging.new(Rails.logger)
  end

  def log(message)
    logger.tagged('MangaDex::Importer', "User ##{@current_user_id}") do
      logger.info message
    end
  end

然后我在我的代码中这样调用它:

    if md_parsed_list.blank?
      log 'List is inaccessible'
      return
    end

现在,在我的 Rspec 测试中,我一直在尝试做这样的事情:

  it 'logs and stops execution if there is nothing to import' do
    expect(Spiders::Mangadex).to receive(:parse!)
      .with(:parse, url: import_url)
      .and_return({})

    expect(ActiveSupport::TaggedLogging).to receive(Rails.logger)
    expect(Rails.logger).to receive(:info).with('List is inaccessible')
    expect(CreateMangaEntries).not_to receive(:call)

    described_class.perform_async(import_url, user.id)
    described_class.drain
  end

我知道我在连接 TaggedLogging 和 Rails.logger 时缺少一些步骤,因为调用上面的测试只会引发错误undefined method 'to_sym' for #<ActiveSupport::Logger:0x00007f8fc545db50>

希望对此有所帮助,在此先感谢!

编辑:

在基于@Grzegorz 改进了所涉及的模拟之后,测试最终看起来像这样:

  let(:tagged_logger_double) { instance_double(ActiveSupport::Logger) }

  it 'logs and stops execution if MDList is inaccessible' do
    expect(Spiders::Mangadex).to receive(:parse!)
      .with(:parse, url: import_url)
      .and_return(nil)
    expect(ActiveSupport::TaggedLogging)
      .to receive(:new)
      .with(Rails.logger)
      .and_return(tagged_logger_double)
    expect(CreateMangaEntries).not_to receive(:call)
    expect(tagged_logger_double).to receive(:info).with('List is inaccessible')

    described_class.perform_async(import_url, user.id)
    described_class.drain
  end

由于存在的实例,我不得不稍微改变双ActiveSupport::TaggedLogging精度ActiveSupport::Logger

我能够解决原始异常,但仍然无法测试receive(:info),因为tagged似乎缺少: #<InstanceDouble(ActiveSupport::Logger) (anonymous)> received unexpected message :tagged with ("MangaDex::Importer", "User #2626")

但是,当我也尝试对该方法进行存根时:allow(tagged_logger_double).to receive(:tagged),我得到了这种方法不存在的错误:the ActiveSupport::Logger class does not implement the instance method: tagged,我仍然被失败的测试困住了。

标签: ruby-on-railsloggingrspecruby-on-rails-6

解决方案


Grzegorz 正确回答了你问题的第一部分,所以从他离开的地方继续......

你是对的,你需要 stub tagged。您收到方法未实现错误的原因是因为ActiveSupport::Logger未实现tagged. 它在被 包裹时被扩展ActiveSupport::TaggedLogging

在此处查看构造函数方法定义:https ://api.rubyonrails.org/classes/ActiveSupport/TaggedLogging.html#method-c-new

在这种情况下,我不确定如何使用验证替身。一种选择是不这样做,而只使用double.

另一个问题是你没有tagged正确存根。您需要对它进行存根,以便它屈服于块。

最后,您需要记住logger方法的返回值,因为您只希望ActiveSupport::TaggedLogging收到new一次。

将所有这些结合在一起,我编写了以下测试:

require "rails_helper"
require "custom_logger"

RSpec.describe "CustomLogger" do
  let(:tagged_logger_double) { double("Tagged logger") }

  it "logs" do
    expect(ActiveSupport::TaggedLogging)
      .to receive(:new)
      .with(Rails.logger)
      .and_return(tagged_logger_double)

    allow(tagged_logger_double)
      .to receive(:tagged)
      .and_yield

    expect(tagged_logger_double).to receive(:info).with("message")

    CustomLogger.new.log("message")
  end
end

这通过以下代码传递,我认为这与您的示例非常相似:

class CustomLogger
  def log(message)
    logger.tagged("Tag") do
      logger.info message
    end
  end

  def logger
    @_logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
  end
end

推荐阅读