Dave Schweisguth Dave Schweisguth - 3 months ago 9
Ruby Question

In RSpec, how to determine the time each spec file takes to run?

Background: My project's continuous integration build runs RSpec in several parallel runs. Specs are partitioned across parallel runs by spec file. That means long spec files dominate test suite run time. So I want to know the time each spec file takes to run (not just the time each example takes to run).

How can I get RSpec to tell me the time each spec file takes to run? Several of RSpec's stock formatters tell me the time each example takes to run, but they don't sum the time for each spec.

I'm using RSpec 3.2.

Answer

I addressed this need by writing my own RSpec formatter. Put the following class in spec/support, make sure it's required, and run rspec like so:

rspec --format SpecTimeFormatter --out spec-times.txt

class SpecTimeFormatter < RSpec::Core::Formatters::BaseFormatter
  RSpec::Core::Formatters.register self, :example_started, :stop

  def initialize(output)
    @output = output
    @times = []
  end

  def example_started(notification)
    current_spec = notification.example.file_path
    if current_spec != @current_spec
      if @current_spec_start_time
        save_current_spec_time
      end
      @current_spec = current_spec
      @current_spec_start_time = Time.now
    end
  end

  def stop(_notification)
    save_current_spec_time
    @times.
      sort_by { |_spec, time| -time }.
      each { |spec, time| @output << "#{'%4d' % time} seconds #{spec}\n" }
  end

  private

  def save_current_spec_time
    @times << [@current_spec, (Time.now - @current_spec_start_time).to_i]
  end

end