如何测试ActiveSupport::TaggedLogging
How to test 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
,但我仍然遇到失败的测试。
您已将一个对象传递给 .to receive
方法,它需要一个方法名称(字符串或符号)。这是你错误的根源,下面这个对我来说更有意义:
expect(ActiveSupport::TaggedLogging)
.to receive(:new)
.with(Rails.logger)
.and_return(tagged_logger_double)
如果您这样定义记录器,那么您将拥有对规范中记录器的完全访问权限
let(:tagged_logger_double) { instance_double(ActiveSupport::TaggedLogging) }
并设定您的期望
expect(tagged_logger_double).to receive(:info).with('List is inaccessible')
Grzegorz 正确回答了你问题的第一部分,所以从他停下的地方继续...
你是对的,你需要存根 tagged
。你得到方法未实现错误的原因是因为 ActiveSupport::Logger
没有实现 tagged
。它在被 ActiveSupport::TaggedLogging
.
包裹时被扩展
在此处查看构造方法定义:https://api.rubyonrails.org/classes/ActiveSupport/TaggedLogging.html#method-c-new
我不确定在这种情况下如何使用验证替身。一种选择是不这样做,只使用 double
.
另一个问题是你没有正确地存根 tagged
。您需要存根以便它屈服于块。
最后,您需要记住 logger
方法的 return 值,因为您只希望 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
我需要测试已记录的标签和消息。
此代码对我有用。
let(:logger) { ActiveSupport::TaggedLogging.new(Rails.logger) }
before do
allow(logger).to receive(:tagged).and_call_original
allow(logger).to receive(:info).and_call_original
allow(ActiveSupport::TaggedLogging).to receive(:new).and_return(logger)
end
it 'logs with correct tags' do
expect(logger).to have_received(:tagged).with(tags)
end
it 'logs with correct message' do
expect(logger).to have_received(:info).with(message)
end
我想测试我在代码中生成的特定日志。虽然测试 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
,但我仍然遇到失败的测试。
您已将一个对象传递给 .to receive
方法,它需要一个方法名称(字符串或符号)。这是你错误的根源,下面这个对我来说更有意义:
expect(ActiveSupport::TaggedLogging)
.to receive(:new)
.with(Rails.logger)
.and_return(tagged_logger_double)
如果您这样定义记录器,那么您将拥有对规范中记录器的完全访问权限
let(:tagged_logger_double) { instance_double(ActiveSupport::TaggedLogging) }
并设定您的期望
expect(tagged_logger_double).to receive(:info).with('List is inaccessible')
Grzegorz 正确回答了你问题的第一部分,所以从他停下的地方继续...
你是对的,你需要存根 tagged
。你得到方法未实现错误的原因是因为 ActiveSupport::Logger
没有实现 tagged
。它在被 ActiveSupport::TaggedLogging
.
在此处查看构造方法定义:https://api.rubyonrails.org/classes/ActiveSupport/TaggedLogging.html#method-c-new
我不确定在这种情况下如何使用验证替身。一种选择是不这样做,只使用 double
.
另一个问题是你没有正确地存根 tagged
。您需要存根以便它屈服于块。
最后,您需要记住 logger
方法的 return 值,因为您只希望 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
我需要测试已记录的标签和消息。 此代码对我有用。
let(:logger) { ActiveSupport::TaggedLogging.new(Rails.logger) }
before do
allow(logger).to receive(:tagged).and_call_original
allow(logger).to receive(:info).and_call_original
allow(ActiveSupport::TaggedLogging).to receive(:new).and_return(logger)
end
it 'logs with correct tags' do
expect(logger).to have_received(:tagged).with(tags)
end
it 'logs with correct message' do
expect(logger).to have_received(:info).with(message)
end