自定义RSpec格式化程序显示通过测试和结果除外

时间:2018-01-05 15:00:02

标签: ruby rspec integration-testing

有没有办法创建一个自定义格式化程序,其中显示传递的测试详细信息,并显示除了列表?

这个问题的背景知识:我们正在尝试迁移到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

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

最后在我的同事的帮助下,感谢Tip from RSPec Emailing list我能做到这一点。

我创建了一个收集测试结果的Recorder类,而不是覆盖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

答案 1 :(得分:0)

我想你可以阅读Module: RSpec::Core::Formatters

你可能会发现一些有用的东西。

P.S。我曾经多次使用过Cucumber,我曾经想要定制黄瓜格式化程序来显示每一步的细节,无论它失败还是过去。我终于通过阅读黄瓜核心文件得到了解决方案。所以我想也许rspec核心文档可以帮助你找到解决方案。

答案 2 :(得分:0)

我发现我不能把代码放在评论中,所以我把它放在这里。 编辑您的代码如下:

class EliteReporter
  RSpec::Core::Formatters.register self, :example_started, :example_passed, :example_failed, :example_finished
  def example_passed(example)
      example_failed(example)
  end
end

我希望它有用:)