自定义 RSpec 格式化程序以显示通过的测试和 except 的结果
Custom RSpec formatter to display passed test and result of except
有没有办法创建一个自定义格式化程序,其中显示已通过的测试详细信息以及例外列表?
这个问题的一些背景知识:我们正在尝试迁移到 RSpec 以进行硬件集成和系统测试。结果应该被推送到 CouchDB。我想要实现的是一个可以生成类似于以下代码段的类似 YAML 输出的记者:
{
"_id": "0006b6f0-c1bd-0135-1a98-455c37fe87f1",
"_rev": "1-9c9786b4b4681ee8493f182d4fc56ef9",
"sha1_repo": "68bb327b540097c10683830f0d82acbe54a47f03",
"steps": [
{
"result": "pass",
"description": "Time for Routing expect OK: 126 micro seconds (DLC and Data also OK)"
},
{
"result": "pass",
"description": "Time for Routing expect OK: 146 micro seconds (DLC and Data also OK)"
},
{
"result": "pass",
"description": "Time for Routing expect OK: 162 micro seconds (DLC and Data also OK)"
}
],
"time_start": "1513119108000",
"time_end": "1513119108000",
"result": "pass",
"testcase_title": "Komfort_TSG_HBFS_03_to_Komfort2_TSG_HBFS_03",
"testcase_id": "TC_1zu1_BAF_Komfort_TSG_HBFS_03_to_Komfort2_TSG_HBFS_03",
"hierarchy": [
"Hardware Integration Test",
"1 - Routing",
"1.1 Normal Routing",
"1zu1_BAF_TestCases",
"CAN_to_CAN"
]
}
通过失败的测试,实现这一目标没有问题,但我们还需要通过测试的结果,以便能够创建长期统计数据。
我可以覆盖 RSPec 传递的事件,但示例对象只提供描述,没有更多信息。
class EliteReporter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def example_passed(passed)
@output.printf "pass \n #{passed.example.description}"
end
end
提前感谢您的帮助。
我想你可以阅读 Module: RSpec::Core::Formatters
您可能会发现一些有用的东西。
P.S。我用过很多次 Cucumber,曾经想自定义 cucumber formatter 来显示每一步的细节,不管是失败还是通过。我终于通过阅读 cucumber 核心找到了解决方案 documents.so 我想也许 rspec 核心文档可以帮助您找到解决方案。
我发现我不能把代码放在注释里,所以我把它放在这里。
按如下方式编辑您的代码:
class EliteReporter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def example_passed(example)
example_failed(example)
end
end
希望对您有所帮助:)
终于在我同事的帮助下,感谢 Tip from RSPec Emailing list 我可以做到这一点。
我创建了一个收集测试结果的记录器 class,而不是覆盖 Expect 方法。这样在自定义格式化程序中我可以收集所有传递的结果:
class ExpectWrapper
def initialize(_expect, _recorder, _description)
@expect = _expect
@recorder = _recorder
@description = _description
end
def to(matcher, failure_message=nil)
begin
expect_ret = @expect.to(matcher, failure_message) # test
# for tests that aggregate failures
if expect_ret.instance_of?(TrueClass)
@recorder.record(matcher.actual, matcher.description, @description)
else
@recorder.record_error(matcher.actual, matcher.description, failure_message, @description)
end
expect_ret
rescue RSpec::Expectations::ExpectationNotMetError => e
# for test that do not aggregate failures
@recorder.record_error(matcher.actual, matcher.description, failure_message, @description)
raise e
end
end
end
class Recorder
def self.start
@@data = []
return Recorder.new
end
def record(expect, data, description)
@@data << { :pass => true, :expect => expect, :value => data, :description => description }
self
end
def record_error(expect, data, failure_message, description)
@@data << { :pass => false, :expect => expect, :value => data, :message => failure_message, :description => description }
self
end
def self.data
@@data
end
def expect(object, value, description = "")
return ExpectWrapper.new(object.expect(value), self, description)
end
end
自定义格式化程序如下所示,这只是一个示例,数据可能会被放入 JSON 并推送到 Couch:
class EliteVerboseFormatter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def initialize(output)
@output = output
end
def example_passed(notification)
@output.puts( format_output(notification.example, Recorder) )
end
def get_test_name( group, description)
"#{group.example.example_group}/#{description}".gsub('RSpec::ExampleGroups::','')
end
def format_output( example, recorder )
test_case = get_test_name( example.example_group, example.description)
str = "**********TEST: #{test_case} ************\n"
recorder.data.each do |d|
str += sprintf("%s: ---> expected '%-10s' to '%-20s' DESC: %s \n", d[:pass] ? 'PASS' : 'FAIL', d[:expect], d[:value], d[:description])
end
str
end
def example_failed(notification)
@output.puts(format_output( notification.example, Recorder))
exception = notification.exception
message_lines = notification.fully_formatted_lines(nil, RSpec::Core::Notifications::NullColorizer)
exception_details = if exception
{
# drop 2 removes the description (regardless of newlines) and leading blank line
:message => message_lines.drop(2).join("\n"),
:backtrace => notification.formatted_backtrace.join("\n"),
}
end
@output.puts RSpec::Core::Formatters::ConsoleCodes.wrap(exception_details[:message], :failure)
end
end
有没有办法创建一个自定义格式化程序,其中显示已通过的测试详细信息以及例外列表?
这个问题的一些背景知识:我们正在尝试迁移到 RSpec 以进行硬件集成和系统测试。结果应该被推送到 CouchDB。我想要实现的是一个可以生成类似于以下代码段的类似 YAML 输出的记者:
{
"_id": "0006b6f0-c1bd-0135-1a98-455c37fe87f1",
"_rev": "1-9c9786b4b4681ee8493f182d4fc56ef9",
"sha1_repo": "68bb327b540097c10683830f0d82acbe54a47f03",
"steps": [
{
"result": "pass",
"description": "Time for Routing expect OK: 126 micro seconds (DLC and Data also OK)"
},
{
"result": "pass",
"description": "Time for Routing expect OK: 146 micro seconds (DLC and Data also OK)"
},
{
"result": "pass",
"description": "Time for Routing expect OK: 162 micro seconds (DLC and Data also OK)"
}
],
"time_start": "1513119108000",
"time_end": "1513119108000",
"result": "pass",
"testcase_title": "Komfort_TSG_HBFS_03_to_Komfort2_TSG_HBFS_03",
"testcase_id": "TC_1zu1_BAF_Komfort_TSG_HBFS_03_to_Komfort2_TSG_HBFS_03",
"hierarchy": [
"Hardware Integration Test",
"1 - Routing",
"1.1 Normal Routing",
"1zu1_BAF_TestCases",
"CAN_to_CAN"
]
}
通过失败的测试,实现这一目标没有问题,但我们还需要通过测试的结果,以便能够创建长期统计数据。
我可以覆盖 RSPec 传递的事件,但示例对象只提供描述,没有更多信息。
class EliteReporter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def example_passed(passed)
@output.printf "pass \n #{passed.example.description}"
end
end
提前感谢您的帮助。
我想你可以阅读 Module: RSpec::Core::Formatters
您可能会发现一些有用的东西。
P.S。我用过很多次 Cucumber,曾经想自定义 cucumber formatter 来显示每一步的细节,不管是失败还是通过。我终于通过阅读 cucumber 核心找到了解决方案 documents.so 我想也许 rspec 核心文档可以帮助您找到解决方案。
我发现我不能把代码放在注释里,所以我把它放在这里。 按如下方式编辑您的代码:
class EliteReporter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def example_passed(example)
example_failed(example)
end
end
希望对您有所帮助:)
终于在我同事的帮助下,感谢 Tip from RSPec Emailing list 我可以做到这一点。
我创建了一个收集测试结果的记录器 class,而不是覆盖 Expect 方法。这样在自定义格式化程序中我可以收集所有传递的结果:
class ExpectWrapper
def initialize(_expect, _recorder, _description)
@expect = _expect
@recorder = _recorder
@description = _description
end
def to(matcher, failure_message=nil)
begin
expect_ret = @expect.to(matcher, failure_message) # test
# for tests that aggregate failures
if expect_ret.instance_of?(TrueClass)
@recorder.record(matcher.actual, matcher.description, @description)
else
@recorder.record_error(matcher.actual, matcher.description, failure_message, @description)
end
expect_ret
rescue RSpec::Expectations::ExpectationNotMetError => e
# for test that do not aggregate failures
@recorder.record_error(matcher.actual, matcher.description, failure_message, @description)
raise e
end
end
end
class Recorder
def self.start
@@data = []
return Recorder.new
end
def record(expect, data, description)
@@data << { :pass => true, :expect => expect, :value => data, :description => description }
self
end
def record_error(expect, data, failure_message, description)
@@data << { :pass => false, :expect => expect, :value => data, :message => failure_message, :description => description }
self
end
def self.data
@@data
end
def expect(object, value, description = "")
return ExpectWrapper.new(object.expect(value), self, description)
end
end
自定义格式化程序如下所示,这只是一个示例,数据可能会被放入 JSON 并推送到 Couch:
class EliteVerboseFormatter
RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
def initialize(output)
@output = output
end
def example_passed(notification)
@output.puts( format_output(notification.example, Recorder) )
end
def get_test_name( group, description)
"#{group.example.example_group}/#{description}".gsub('RSpec::ExampleGroups::','')
end
def format_output( example, recorder )
test_case = get_test_name( example.example_group, example.description)
str = "**********TEST: #{test_case} ************\n"
recorder.data.each do |d|
str += sprintf("%s: ---> expected '%-10s' to '%-20s' DESC: %s \n", d[:pass] ? 'PASS' : 'FAIL', d[:expect], d[:value], d[:description])
end
str
end
def example_failed(notification)
@output.puts(format_output( notification.example, Recorder))
exception = notification.exception
message_lines = notification.fully_formatted_lines(nil, RSpec::Core::Notifications::NullColorizer)
exception_details = if exception
{
# drop 2 removes the description (regardless of newlines) and leading blank line
:message => message_lines.drop(2).join("\n"),
:backtrace => notification.formatted_backtrace.join("\n"),
}
end
@output.puts RSpec::Core::Formatters::ConsoleCodes.wrap(exception_details[:message], :failure)
end
end